1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | // |
3 | // pin-controller/pin-mux/pin-config/gpio-driver for Samsung's SoC's. |
4 | // |
5 | // Copyright (c) 2012 Samsung Electronics Co., Ltd. |
6 | // http://www.samsung.com |
7 | // Copyright (c) 2012 Linaro Ltd |
8 | // http://www.linaro.org |
9 | // |
10 | // Author: Thomas Abraham <thomas.ab@samsung.com> |
11 | // |
12 | // This driver implements the Samsung pinctrl driver. It supports setting up of |
13 | // pinmux and pinconf configurations. The gpiolib interface is also included. |
14 | // External interrupt (gpio and wakeup) support are not included in this driver |
15 | // but provides extensions to which platform specific implementation of the gpio |
16 | // and wakeup interrupts can be hooked to. |
17 | |
18 | #include <linux/err.h> |
19 | #include <linux/gpio/driver.h> |
20 | #include <linux/init.h> |
21 | #include <linux/io.h> |
22 | #include <linux/irqdomain.h> |
23 | #include <linux/of.h> |
24 | #include <linux/platform_device.h> |
25 | #include <linux/property.h> |
26 | #include <linux/seq_file.h> |
27 | #include <linux/slab.h> |
28 | #include <linux/spinlock.h> |
29 | |
30 | #include "../core.h" |
31 | #include "pinctrl-samsung.h" |
32 | |
33 | /* maximum number of the memory resources */ |
34 | #define SAMSUNG_PINCTRL_NUM_RESOURCES 2 |
35 | |
36 | /* list of all possible config options supported */ |
37 | static struct pin_config { |
38 | const char *property; |
39 | enum pincfg_type param; |
40 | } cfg_params[] = { |
41 | { "samsung,pin-pud" , PINCFG_TYPE_PUD }, |
42 | { "samsung,pin-drv" , PINCFG_TYPE_DRV }, |
43 | { "samsung,pin-con-pdn" , PINCFG_TYPE_CON_PDN }, |
44 | { "samsung,pin-pud-pdn" , PINCFG_TYPE_PUD_PDN }, |
45 | { "samsung,pin-val" , PINCFG_TYPE_DAT }, |
46 | }; |
47 | |
48 | static int samsung_get_group_count(struct pinctrl_dev *pctldev) |
49 | { |
50 | struct samsung_pinctrl_drv_data *pmx = pinctrl_dev_get_drvdata(pctldev); |
51 | |
52 | return pmx->nr_groups; |
53 | } |
54 | |
55 | static const char *samsung_get_group_name(struct pinctrl_dev *pctldev, |
56 | unsigned group) |
57 | { |
58 | struct samsung_pinctrl_drv_data *pmx = pinctrl_dev_get_drvdata(pctldev); |
59 | |
60 | return pmx->pin_groups[group].name; |
61 | } |
62 | |
63 | static int samsung_get_group_pins(struct pinctrl_dev *pctldev, |
64 | unsigned group, |
65 | const unsigned **pins, |
66 | unsigned *num_pins) |
67 | { |
68 | struct samsung_pinctrl_drv_data *pmx = pinctrl_dev_get_drvdata(pctldev); |
69 | |
70 | *pins = pmx->pin_groups[group].pins; |
71 | *num_pins = pmx->pin_groups[group].num_pins; |
72 | |
73 | return 0; |
74 | } |
75 | |
76 | static int reserve_map(struct device *dev, struct pinctrl_map **map, |
77 | unsigned *reserved_maps, unsigned *num_maps, |
78 | unsigned reserve) |
79 | { |
80 | unsigned old_num = *reserved_maps; |
81 | unsigned new_num = *num_maps + reserve; |
82 | struct pinctrl_map *new_map; |
83 | |
84 | if (old_num >= new_num) |
85 | return 0; |
86 | |
87 | new_map = krealloc(objp: *map, new_size: sizeof(*new_map) * new_num, GFP_KERNEL); |
88 | if (!new_map) |
89 | return -ENOMEM; |
90 | |
91 | memset(new_map + old_num, 0, (new_num - old_num) * sizeof(*new_map)); |
92 | |
93 | *map = new_map; |
94 | *reserved_maps = new_num; |
95 | |
96 | return 0; |
97 | } |
98 | |
99 | static int add_map_mux(struct pinctrl_map **map, unsigned *reserved_maps, |
100 | unsigned *num_maps, const char *group, |
101 | const char *function) |
102 | { |
103 | if (WARN_ON(*num_maps == *reserved_maps)) |
104 | return -ENOSPC; |
105 | |
106 | (*map)[*num_maps].type = PIN_MAP_TYPE_MUX_GROUP; |
107 | (*map)[*num_maps].data.mux.group = group; |
108 | (*map)[*num_maps].data.mux.function = function; |
109 | (*num_maps)++; |
110 | |
111 | return 0; |
112 | } |
113 | |
114 | static int add_map_configs(struct device *dev, struct pinctrl_map **map, |
115 | unsigned *reserved_maps, unsigned *num_maps, |
116 | const char *group, unsigned long *configs, |
117 | unsigned num_configs) |
118 | { |
119 | unsigned long *dup_configs; |
120 | |
121 | if (WARN_ON(*num_maps == *reserved_maps)) |
122 | return -ENOSPC; |
123 | |
124 | dup_configs = kmemdup(p: configs, size: num_configs * sizeof(*dup_configs), |
125 | GFP_KERNEL); |
126 | if (!dup_configs) |
127 | return -ENOMEM; |
128 | |
129 | (*map)[*num_maps].type = PIN_MAP_TYPE_CONFIGS_GROUP; |
130 | (*map)[*num_maps].data.configs.group_or_pin = group; |
131 | (*map)[*num_maps].data.configs.configs = dup_configs; |
132 | (*map)[*num_maps].data.configs.num_configs = num_configs; |
133 | (*num_maps)++; |
134 | |
135 | return 0; |
136 | } |
137 | |
138 | static int add_config(struct device *dev, unsigned long **configs, |
139 | unsigned *num_configs, unsigned long config) |
140 | { |
141 | unsigned old_num = *num_configs; |
142 | unsigned new_num = old_num + 1; |
143 | unsigned long *new_configs; |
144 | |
145 | new_configs = krealloc(objp: *configs, new_size: sizeof(*new_configs) * new_num, |
146 | GFP_KERNEL); |
147 | if (!new_configs) |
148 | return -ENOMEM; |
149 | |
150 | new_configs[old_num] = config; |
151 | |
152 | *configs = new_configs; |
153 | *num_configs = new_num; |
154 | |
155 | return 0; |
156 | } |
157 | |
158 | static void samsung_dt_free_map(struct pinctrl_dev *pctldev, |
159 | struct pinctrl_map *map, |
160 | unsigned num_maps) |
161 | { |
162 | int i; |
163 | |
164 | for (i = 0; i < num_maps; i++) |
165 | if (map[i].type == PIN_MAP_TYPE_CONFIGS_GROUP) |
166 | kfree(objp: map[i].data.configs.configs); |
167 | |
168 | kfree(objp: map); |
169 | } |
170 | |
171 | static int samsung_dt_subnode_to_map(struct samsung_pinctrl_drv_data *drvdata, |
172 | struct device *dev, |
173 | struct device_node *np, |
174 | struct pinctrl_map **map, |
175 | unsigned *reserved_maps, |
176 | unsigned *num_maps) |
177 | { |
178 | int ret, i; |
179 | u32 val; |
180 | unsigned long config; |
181 | unsigned long *configs = NULL; |
182 | unsigned num_configs = 0; |
183 | unsigned reserve; |
184 | struct property *prop; |
185 | const char *group; |
186 | bool has_func = false; |
187 | |
188 | ret = of_property_read_u32(np, propname: "samsung,pin-function" , out_value: &val); |
189 | if (!ret) |
190 | has_func = true; |
191 | |
192 | for (i = 0; i < ARRAY_SIZE(cfg_params); i++) { |
193 | ret = of_property_read_u32(np, propname: cfg_params[i].property, out_value: &val); |
194 | if (!ret) { |
195 | config = PINCFG_PACK(cfg_params[i].param, val); |
196 | ret = add_config(dev, configs: &configs, num_configs: &num_configs, config); |
197 | if (ret < 0) |
198 | goto exit; |
199 | /* EINVAL=missing, which is fine since it's optional */ |
200 | } else if (ret != -EINVAL) { |
201 | dev_err(dev, "could not parse property %s\n" , |
202 | cfg_params[i].property); |
203 | } |
204 | } |
205 | |
206 | reserve = 0; |
207 | if (has_func) |
208 | reserve++; |
209 | if (num_configs) |
210 | reserve++; |
211 | ret = of_property_count_strings(np, propname: "samsung,pins" ); |
212 | if (ret < 0) { |
213 | dev_err(dev, "could not parse property samsung,pins\n" ); |
214 | goto exit; |
215 | } |
216 | reserve *= ret; |
217 | |
218 | ret = reserve_map(dev, map, reserved_maps, num_maps, reserve); |
219 | if (ret < 0) |
220 | goto exit; |
221 | |
222 | of_property_for_each_string(np, "samsung,pins" , prop, group) { |
223 | if (has_func) { |
224 | ret = add_map_mux(map, reserved_maps, |
225 | num_maps, group, function: np->full_name); |
226 | if (ret < 0) |
227 | goto exit; |
228 | } |
229 | |
230 | if (num_configs) { |
231 | ret = add_map_configs(dev, map, reserved_maps, |
232 | num_maps, group, configs, |
233 | num_configs); |
234 | if (ret < 0) |
235 | goto exit; |
236 | } |
237 | } |
238 | |
239 | ret = 0; |
240 | |
241 | exit: |
242 | kfree(objp: configs); |
243 | return ret; |
244 | } |
245 | |
246 | static int samsung_dt_node_to_map(struct pinctrl_dev *pctldev, |
247 | struct device_node *np_config, |
248 | struct pinctrl_map **map, |
249 | unsigned *num_maps) |
250 | { |
251 | struct samsung_pinctrl_drv_data *drvdata; |
252 | unsigned reserved_maps; |
253 | struct device_node *np; |
254 | int ret; |
255 | |
256 | drvdata = pinctrl_dev_get_drvdata(pctldev); |
257 | |
258 | reserved_maps = 0; |
259 | *map = NULL; |
260 | *num_maps = 0; |
261 | |
262 | if (!of_get_child_count(np: np_config)) |
263 | return samsung_dt_subnode_to_map(drvdata, dev: pctldev->dev, |
264 | np: np_config, map, |
265 | reserved_maps: &reserved_maps, |
266 | num_maps); |
267 | |
268 | for_each_child_of_node(np_config, np) { |
269 | ret = samsung_dt_subnode_to_map(drvdata, dev: pctldev->dev, np, map, |
270 | reserved_maps: &reserved_maps, num_maps); |
271 | if (ret < 0) { |
272 | samsung_dt_free_map(pctldev, map: *map, num_maps: *num_maps); |
273 | of_node_put(node: np); |
274 | return ret; |
275 | } |
276 | } |
277 | |
278 | return 0; |
279 | } |
280 | |
281 | #ifdef CONFIG_DEBUG_FS |
282 | /* Forward declaration which can be used by samsung_pin_dbg_show */ |
283 | static int samsung_pinconf_get(struct pinctrl_dev *pctldev, unsigned int pin, |
284 | unsigned long *config); |
285 | static const char * const reg_names[] = {"CON" , "DAT" , "PUD" , "DRV" , "CON_PDN" , |
286 | "PUD_PDN" }; |
287 | |
288 | static void samsung_pin_dbg_show(struct pinctrl_dev *pctldev, |
289 | struct seq_file *s, unsigned int pin) |
290 | { |
291 | enum pincfg_type cfg_type; |
292 | unsigned long config; |
293 | int ret; |
294 | |
295 | for (cfg_type = 0; cfg_type < PINCFG_TYPE_NUM; cfg_type++) { |
296 | config = PINCFG_PACK(cfg_type, 0); |
297 | ret = samsung_pinconf_get(pctldev, pin, config: &config); |
298 | if (ret < 0) |
299 | continue; |
300 | |
301 | seq_printf(m: s, fmt: " %s(0x%lx)" , reg_names[cfg_type], |
302 | PINCFG_UNPACK_VALUE(config)); |
303 | } |
304 | } |
305 | #endif |
306 | |
307 | /* list of pinctrl callbacks for the pinctrl core */ |
308 | static const struct pinctrl_ops samsung_pctrl_ops = { |
309 | .get_groups_count = samsung_get_group_count, |
310 | .get_group_name = samsung_get_group_name, |
311 | .get_group_pins = samsung_get_group_pins, |
312 | .dt_node_to_map = samsung_dt_node_to_map, |
313 | .dt_free_map = samsung_dt_free_map, |
314 | #ifdef CONFIG_DEBUG_FS |
315 | .pin_dbg_show = samsung_pin_dbg_show, |
316 | #endif |
317 | }; |
318 | |
319 | /* check if the selector is a valid pin function selector */ |
320 | static int samsung_get_functions_count(struct pinctrl_dev *pctldev) |
321 | { |
322 | struct samsung_pinctrl_drv_data *drvdata; |
323 | |
324 | drvdata = pinctrl_dev_get_drvdata(pctldev); |
325 | return drvdata->nr_functions; |
326 | } |
327 | |
328 | /* return the name of the pin function specified */ |
329 | static const char *samsung_pinmux_get_fname(struct pinctrl_dev *pctldev, |
330 | unsigned selector) |
331 | { |
332 | struct samsung_pinctrl_drv_data *drvdata; |
333 | |
334 | drvdata = pinctrl_dev_get_drvdata(pctldev); |
335 | return drvdata->pmx_functions[selector].name; |
336 | } |
337 | |
338 | /* return the groups associated for the specified function selector */ |
339 | static int samsung_pinmux_get_groups(struct pinctrl_dev *pctldev, |
340 | unsigned selector, const char * const **groups, |
341 | unsigned * const num_groups) |
342 | { |
343 | struct samsung_pinctrl_drv_data *drvdata; |
344 | |
345 | drvdata = pinctrl_dev_get_drvdata(pctldev); |
346 | *groups = drvdata->pmx_functions[selector].groups; |
347 | *num_groups = drvdata->pmx_functions[selector].num_groups; |
348 | return 0; |
349 | } |
350 | |
351 | /* |
352 | * given a pin number that is local to a pin controller, find out the pin bank |
353 | * and the register base of the pin bank. |
354 | */ |
355 | static void pin_to_reg_bank(struct samsung_pinctrl_drv_data *drvdata, |
356 | unsigned pin, void __iomem **reg, u32 *offset, |
357 | struct samsung_pin_bank **bank) |
358 | { |
359 | struct samsung_pin_bank *b; |
360 | |
361 | b = drvdata->pin_banks; |
362 | |
363 | while ((pin >= b->pin_base) && |
364 | ((b->pin_base + b->nr_pins - 1) < pin)) |
365 | b++; |
366 | |
367 | *reg = b->pctl_base + b->pctl_offset; |
368 | *offset = pin - b->pin_base; |
369 | if (bank) |
370 | *bank = b; |
371 | } |
372 | |
373 | /* enable or disable a pinmux function */ |
374 | static void samsung_pinmux_setup(struct pinctrl_dev *pctldev, unsigned selector, |
375 | unsigned group) |
376 | { |
377 | struct samsung_pinctrl_drv_data *drvdata; |
378 | const struct samsung_pin_bank_type *type; |
379 | struct samsung_pin_bank *bank; |
380 | void __iomem *reg; |
381 | u32 mask, shift, data, pin_offset; |
382 | unsigned long flags; |
383 | const struct samsung_pmx_func *func; |
384 | const struct samsung_pin_group *grp; |
385 | |
386 | drvdata = pinctrl_dev_get_drvdata(pctldev); |
387 | func = &drvdata->pmx_functions[selector]; |
388 | grp = &drvdata->pin_groups[group]; |
389 | |
390 | pin_to_reg_bank(drvdata, pin: grp->pins[0], reg: ®, offset: &pin_offset, bank: &bank); |
391 | type = bank->type; |
392 | mask = (1 << type->fld_width[PINCFG_TYPE_FUNC]) - 1; |
393 | shift = pin_offset * type->fld_width[PINCFG_TYPE_FUNC]; |
394 | if (shift >= 32) { |
395 | /* Some banks have two config registers */ |
396 | shift -= 32; |
397 | reg += 4; |
398 | } |
399 | |
400 | raw_spin_lock_irqsave(&bank->slock, flags); |
401 | |
402 | data = readl(addr: reg + type->reg_offset[PINCFG_TYPE_FUNC]); |
403 | data &= ~(mask << shift); |
404 | data |= func->val << shift; |
405 | writel(val: data, addr: reg + type->reg_offset[PINCFG_TYPE_FUNC]); |
406 | |
407 | raw_spin_unlock_irqrestore(&bank->slock, flags); |
408 | } |
409 | |
410 | /* enable a specified pinmux by writing to registers */ |
411 | static int samsung_pinmux_set_mux(struct pinctrl_dev *pctldev, |
412 | unsigned selector, |
413 | unsigned group) |
414 | { |
415 | samsung_pinmux_setup(pctldev, selector, group); |
416 | return 0; |
417 | } |
418 | |
419 | /* list of pinmux callbacks for the pinmux vertical in pinctrl core */ |
420 | static const struct pinmux_ops samsung_pinmux_ops = { |
421 | .get_functions_count = samsung_get_functions_count, |
422 | .get_function_name = samsung_pinmux_get_fname, |
423 | .get_function_groups = samsung_pinmux_get_groups, |
424 | .set_mux = samsung_pinmux_set_mux, |
425 | }; |
426 | |
427 | /* set or get the pin config settings for a specified pin */ |
428 | static int samsung_pinconf_rw(struct pinctrl_dev *pctldev, unsigned int pin, |
429 | unsigned long *config, bool set) |
430 | { |
431 | struct samsung_pinctrl_drv_data *drvdata; |
432 | const struct samsung_pin_bank_type *type; |
433 | struct samsung_pin_bank *bank; |
434 | void __iomem *reg_base; |
435 | enum pincfg_type cfg_type = PINCFG_UNPACK_TYPE(*config); |
436 | u32 data, width, pin_offset, mask, shift; |
437 | u32 cfg_value, cfg_reg; |
438 | unsigned long flags; |
439 | |
440 | drvdata = pinctrl_dev_get_drvdata(pctldev); |
441 | pin_to_reg_bank(drvdata, pin, reg: ®_base, offset: &pin_offset, bank: &bank); |
442 | type = bank->type; |
443 | |
444 | if (cfg_type >= PINCFG_TYPE_NUM || !type->fld_width[cfg_type]) |
445 | return -EINVAL; |
446 | |
447 | width = type->fld_width[cfg_type]; |
448 | cfg_reg = type->reg_offset[cfg_type]; |
449 | |
450 | raw_spin_lock_irqsave(&bank->slock, flags); |
451 | |
452 | mask = (1 << width) - 1; |
453 | shift = pin_offset * width; |
454 | data = readl(addr: reg_base + cfg_reg); |
455 | |
456 | if (set) { |
457 | cfg_value = PINCFG_UNPACK_VALUE(*config); |
458 | data &= ~(mask << shift); |
459 | data |= (cfg_value << shift); |
460 | writel(val: data, addr: reg_base + cfg_reg); |
461 | } else { |
462 | data >>= shift; |
463 | data &= mask; |
464 | *config = PINCFG_PACK(cfg_type, data); |
465 | } |
466 | |
467 | raw_spin_unlock_irqrestore(&bank->slock, flags); |
468 | |
469 | return 0; |
470 | } |
471 | |
472 | /* set the pin config settings for a specified pin */ |
473 | static int samsung_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin, |
474 | unsigned long *configs, unsigned num_configs) |
475 | { |
476 | int i, ret; |
477 | |
478 | for (i = 0; i < num_configs; i++) { |
479 | ret = samsung_pinconf_rw(pctldev, pin, config: &configs[i], set: true); |
480 | if (ret < 0) |
481 | return ret; |
482 | } /* for each config */ |
483 | |
484 | return 0; |
485 | } |
486 | |
487 | /* get the pin config settings for a specified pin */ |
488 | static int samsung_pinconf_get(struct pinctrl_dev *pctldev, unsigned int pin, |
489 | unsigned long *config) |
490 | { |
491 | return samsung_pinconf_rw(pctldev, pin, config, set: false); |
492 | } |
493 | |
494 | /* set the pin config settings for a specified pin group */ |
495 | static int samsung_pinconf_group_set(struct pinctrl_dev *pctldev, |
496 | unsigned group, unsigned long *configs, |
497 | unsigned num_configs) |
498 | { |
499 | struct samsung_pinctrl_drv_data *drvdata; |
500 | const unsigned int *pins; |
501 | unsigned int cnt; |
502 | |
503 | drvdata = pinctrl_dev_get_drvdata(pctldev); |
504 | pins = drvdata->pin_groups[group].pins; |
505 | |
506 | for (cnt = 0; cnt < drvdata->pin_groups[group].num_pins; cnt++) |
507 | samsung_pinconf_set(pctldev, pin: pins[cnt], configs, num_configs); |
508 | |
509 | return 0; |
510 | } |
511 | |
512 | /* get the pin config settings for a specified pin group */ |
513 | static int samsung_pinconf_group_get(struct pinctrl_dev *pctldev, |
514 | unsigned int group, unsigned long *config) |
515 | { |
516 | struct samsung_pinctrl_drv_data *drvdata; |
517 | const unsigned int *pins; |
518 | |
519 | drvdata = pinctrl_dev_get_drvdata(pctldev); |
520 | pins = drvdata->pin_groups[group].pins; |
521 | samsung_pinconf_get(pctldev, pin: pins[0], config); |
522 | return 0; |
523 | } |
524 | |
525 | /* list of pinconfig callbacks for pinconfig vertical in the pinctrl code */ |
526 | static const struct pinconf_ops samsung_pinconf_ops = { |
527 | .pin_config_get = samsung_pinconf_get, |
528 | .pin_config_set = samsung_pinconf_set, |
529 | .pin_config_group_get = samsung_pinconf_group_get, |
530 | .pin_config_group_set = samsung_pinconf_group_set, |
531 | }; |
532 | |
533 | /* |
534 | * The samsung_gpio_set_vlaue() should be called with "bank->slock" held |
535 | * to avoid race condition. |
536 | */ |
537 | static void samsung_gpio_set_value(struct gpio_chip *gc, |
538 | unsigned offset, int value) |
539 | { |
540 | struct samsung_pin_bank *bank = gpiochip_get_data(gc); |
541 | const struct samsung_pin_bank_type *type = bank->type; |
542 | void __iomem *reg; |
543 | u32 data; |
544 | |
545 | reg = bank->pctl_base + bank->pctl_offset; |
546 | |
547 | data = readl(addr: reg + type->reg_offset[PINCFG_TYPE_DAT]); |
548 | data &= ~(1 << offset); |
549 | if (value) |
550 | data |= 1 << offset; |
551 | writel(val: data, addr: reg + type->reg_offset[PINCFG_TYPE_DAT]); |
552 | } |
553 | |
554 | /* gpiolib gpio_set callback function */ |
555 | static void samsung_gpio_set(struct gpio_chip *gc, unsigned offset, int value) |
556 | { |
557 | struct samsung_pin_bank *bank = gpiochip_get_data(gc); |
558 | unsigned long flags; |
559 | |
560 | raw_spin_lock_irqsave(&bank->slock, flags); |
561 | samsung_gpio_set_value(gc, offset, value); |
562 | raw_spin_unlock_irqrestore(&bank->slock, flags); |
563 | } |
564 | |
565 | /* gpiolib gpio_get callback function */ |
566 | static int samsung_gpio_get(struct gpio_chip *gc, unsigned offset) |
567 | { |
568 | const void __iomem *reg; |
569 | u32 data; |
570 | struct samsung_pin_bank *bank = gpiochip_get_data(gc); |
571 | const struct samsung_pin_bank_type *type = bank->type; |
572 | |
573 | reg = bank->pctl_base + bank->pctl_offset; |
574 | |
575 | data = readl(addr: reg + type->reg_offset[PINCFG_TYPE_DAT]); |
576 | data >>= offset; |
577 | data &= 1; |
578 | return data; |
579 | } |
580 | |
581 | /* |
582 | * The samsung_gpio_set_direction() should be called with "bank->slock" held |
583 | * to avoid race condition. |
584 | * The calls to gpio_direction_output() and gpio_direction_input() |
585 | * leads to this function call. |
586 | */ |
587 | static int samsung_gpio_set_direction(struct gpio_chip *gc, |
588 | unsigned offset, bool input) |
589 | { |
590 | const struct samsung_pin_bank_type *type; |
591 | struct samsung_pin_bank *bank; |
592 | void __iomem *reg; |
593 | u32 data, mask, shift; |
594 | |
595 | bank = gpiochip_get_data(gc); |
596 | type = bank->type; |
597 | |
598 | reg = bank->pctl_base + bank->pctl_offset |
599 | + type->reg_offset[PINCFG_TYPE_FUNC]; |
600 | |
601 | mask = (1 << type->fld_width[PINCFG_TYPE_FUNC]) - 1; |
602 | shift = offset * type->fld_width[PINCFG_TYPE_FUNC]; |
603 | if (shift >= 32) { |
604 | /* Some banks have two config registers */ |
605 | shift -= 32; |
606 | reg += 4; |
607 | } |
608 | |
609 | data = readl(addr: reg); |
610 | data &= ~(mask << shift); |
611 | if (!input) |
612 | data |= PIN_CON_FUNC_OUTPUT << shift; |
613 | writel(val: data, addr: reg); |
614 | |
615 | return 0; |
616 | } |
617 | |
618 | /* gpiolib gpio_direction_input callback function. */ |
619 | static int samsung_gpio_direction_input(struct gpio_chip *gc, unsigned offset) |
620 | { |
621 | struct samsung_pin_bank *bank = gpiochip_get_data(gc); |
622 | unsigned long flags; |
623 | int ret; |
624 | |
625 | raw_spin_lock_irqsave(&bank->slock, flags); |
626 | ret = samsung_gpio_set_direction(gc, offset, input: true); |
627 | raw_spin_unlock_irqrestore(&bank->slock, flags); |
628 | return ret; |
629 | } |
630 | |
631 | /* gpiolib gpio_direction_output callback function. */ |
632 | static int samsung_gpio_direction_output(struct gpio_chip *gc, unsigned offset, |
633 | int value) |
634 | { |
635 | struct samsung_pin_bank *bank = gpiochip_get_data(gc); |
636 | unsigned long flags; |
637 | int ret; |
638 | |
639 | raw_spin_lock_irqsave(&bank->slock, flags); |
640 | samsung_gpio_set_value(gc, offset, value); |
641 | ret = samsung_gpio_set_direction(gc, offset, input: false); |
642 | raw_spin_unlock_irqrestore(&bank->slock, flags); |
643 | |
644 | return ret; |
645 | } |
646 | |
647 | /* |
648 | * gpiod_to_irq() callback function. Creates a mapping between a GPIO pin |
649 | * and a virtual IRQ, if not already present. |
650 | */ |
651 | static int samsung_gpio_to_irq(struct gpio_chip *gc, unsigned offset) |
652 | { |
653 | struct samsung_pin_bank *bank = gpiochip_get_data(gc); |
654 | unsigned int virq; |
655 | |
656 | if (!bank->irq_domain) |
657 | return -ENXIO; |
658 | |
659 | virq = irq_create_mapping(host: bank->irq_domain, hwirq: offset); |
660 | |
661 | return (virq) ? : -ENXIO; |
662 | } |
663 | |
664 | static int samsung_add_pin_ranges(struct gpio_chip *gc) |
665 | { |
666 | struct samsung_pin_bank *bank = gpiochip_get_data(gc); |
667 | |
668 | bank->grange.name = bank->name; |
669 | bank->grange.id = bank->id; |
670 | bank->grange.pin_base = bank->pin_base; |
671 | bank->grange.base = gc->base; |
672 | bank->grange.npins = bank->nr_pins; |
673 | bank->grange.gc = &bank->gpio_chip; |
674 | pinctrl_add_gpio_range(pctldev: bank->drvdata->pctl_dev, range: &bank->grange); |
675 | |
676 | return 0; |
677 | } |
678 | |
679 | static struct samsung_pin_group *samsung_pinctrl_create_groups( |
680 | struct device *dev, |
681 | struct samsung_pinctrl_drv_data *drvdata, |
682 | unsigned int *cnt) |
683 | { |
684 | struct pinctrl_desc *ctrldesc = &drvdata->pctl; |
685 | struct samsung_pin_group *groups, *grp; |
686 | const struct pinctrl_pin_desc *pdesc; |
687 | int i; |
688 | |
689 | groups = devm_kcalloc(dev, n: ctrldesc->npins, size: sizeof(*groups), |
690 | GFP_KERNEL); |
691 | if (!groups) |
692 | return ERR_PTR(error: -EINVAL); |
693 | grp = groups; |
694 | |
695 | pdesc = ctrldesc->pins; |
696 | for (i = 0; i < ctrldesc->npins; ++i, ++pdesc, ++grp) { |
697 | grp->name = pdesc->name; |
698 | grp->pins = &pdesc->number; |
699 | grp->num_pins = 1; |
700 | } |
701 | |
702 | *cnt = ctrldesc->npins; |
703 | return groups; |
704 | } |
705 | |
706 | static int samsung_pinctrl_create_function(struct device *dev, |
707 | struct samsung_pinctrl_drv_data *drvdata, |
708 | struct device_node *func_np, |
709 | struct samsung_pmx_func *func) |
710 | { |
711 | int npins; |
712 | int ret; |
713 | int i; |
714 | |
715 | if (of_property_read_u32(np: func_np, propname: "samsung,pin-function" , out_value: &func->val)) |
716 | return 0; |
717 | |
718 | npins = of_property_count_strings(np: func_np, propname: "samsung,pins" ); |
719 | if (npins < 1) { |
720 | dev_err(dev, "invalid pin list in %pOFn node" , func_np); |
721 | return -EINVAL; |
722 | } |
723 | |
724 | func->name = func_np->full_name; |
725 | |
726 | func->groups = devm_kcalloc(dev, n: npins, size: sizeof(char *), GFP_KERNEL); |
727 | if (!func->groups) |
728 | return -ENOMEM; |
729 | |
730 | for (i = 0; i < npins; ++i) { |
731 | const char *gname; |
732 | |
733 | ret = of_property_read_string_index(np: func_np, propname: "samsung,pins" , |
734 | index: i, output: &gname); |
735 | if (ret) { |
736 | dev_err(dev, |
737 | "failed to read pin name %d from %pOFn node\n" , |
738 | i, func_np); |
739 | return ret; |
740 | } |
741 | |
742 | func->groups[i] = gname; |
743 | } |
744 | |
745 | func->num_groups = npins; |
746 | return 1; |
747 | } |
748 | |
749 | static struct samsung_pmx_func *samsung_pinctrl_create_functions( |
750 | struct device *dev, |
751 | struct samsung_pinctrl_drv_data *drvdata, |
752 | unsigned int *cnt) |
753 | { |
754 | struct samsung_pmx_func *functions, *func; |
755 | struct device_node *dev_np = dev->of_node; |
756 | struct device_node *cfg_np; |
757 | unsigned int func_cnt = 0; |
758 | int ret; |
759 | |
760 | /* |
761 | * Iterate over all the child nodes of the pin controller node |
762 | * and create pin groups and pin function lists. |
763 | */ |
764 | for_each_child_of_node(dev_np, cfg_np) { |
765 | struct device_node *func_np; |
766 | |
767 | if (!of_get_child_count(np: cfg_np)) { |
768 | if (!of_find_property(np: cfg_np, |
769 | name: "samsung,pin-function" , NULL)) |
770 | continue; |
771 | ++func_cnt; |
772 | continue; |
773 | } |
774 | |
775 | for_each_child_of_node(cfg_np, func_np) { |
776 | if (!of_find_property(np: func_np, |
777 | name: "samsung,pin-function" , NULL)) |
778 | continue; |
779 | ++func_cnt; |
780 | } |
781 | } |
782 | |
783 | functions = devm_kcalloc(dev, n: func_cnt, size: sizeof(*functions), |
784 | GFP_KERNEL); |
785 | if (!functions) |
786 | return ERR_PTR(error: -ENOMEM); |
787 | func = functions; |
788 | |
789 | /* |
790 | * Iterate over all the child nodes of the pin controller node |
791 | * and create pin groups and pin function lists. |
792 | */ |
793 | func_cnt = 0; |
794 | for_each_child_of_node(dev_np, cfg_np) { |
795 | struct device_node *func_np; |
796 | |
797 | if (!of_get_child_count(np: cfg_np)) { |
798 | ret = samsung_pinctrl_create_function(dev, drvdata, |
799 | func_np: cfg_np, func); |
800 | if (ret < 0) { |
801 | of_node_put(node: cfg_np); |
802 | return ERR_PTR(error: ret); |
803 | } |
804 | if (ret > 0) { |
805 | ++func; |
806 | ++func_cnt; |
807 | } |
808 | continue; |
809 | } |
810 | |
811 | for_each_child_of_node(cfg_np, func_np) { |
812 | ret = samsung_pinctrl_create_function(dev, drvdata, |
813 | func_np, func); |
814 | if (ret < 0) { |
815 | of_node_put(node: func_np); |
816 | of_node_put(node: cfg_np); |
817 | return ERR_PTR(error: ret); |
818 | } |
819 | if (ret > 0) { |
820 | ++func; |
821 | ++func_cnt; |
822 | } |
823 | } |
824 | } |
825 | |
826 | *cnt = func_cnt; |
827 | return functions; |
828 | } |
829 | |
830 | /* |
831 | * Parse the information about all the available pin groups and pin functions |
832 | * from device node of the pin-controller. A pin group is formed with all |
833 | * the pins listed in the "samsung,pins" property. |
834 | */ |
835 | |
836 | static int samsung_pinctrl_parse_dt(struct platform_device *pdev, |
837 | struct samsung_pinctrl_drv_data *drvdata) |
838 | { |
839 | struct device *dev = &pdev->dev; |
840 | struct samsung_pin_group *groups; |
841 | struct samsung_pmx_func *functions; |
842 | unsigned int grp_cnt = 0, func_cnt = 0; |
843 | |
844 | groups = samsung_pinctrl_create_groups(dev, drvdata, cnt: &grp_cnt); |
845 | if (IS_ERR(ptr: groups)) { |
846 | dev_err(dev, "failed to parse pin groups\n" ); |
847 | return PTR_ERR(ptr: groups); |
848 | } |
849 | |
850 | functions = samsung_pinctrl_create_functions(dev, drvdata, cnt: &func_cnt); |
851 | if (IS_ERR(ptr: functions)) { |
852 | dev_err(dev, "failed to parse pin functions\n" ); |
853 | return PTR_ERR(ptr: functions); |
854 | } |
855 | |
856 | drvdata->pin_groups = groups; |
857 | drvdata->nr_groups = grp_cnt; |
858 | drvdata->pmx_functions = functions; |
859 | drvdata->nr_functions = func_cnt; |
860 | |
861 | return 0; |
862 | } |
863 | |
864 | /* register the pinctrl interface with the pinctrl subsystem */ |
865 | static int samsung_pinctrl_register(struct platform_device *pdev, |
866 | struct samsung_pinctrl_drv_data *drvdata) |
867 | { |
868 | struct pinctrl_desc *ctrldesc = &drvdata->pctl; |
869 | struct pinctrl_pin_desc *pindesc, *pdesc; |
870 | struct samsung_pin_bank *pin_bank; |
871 | char *pin_names; |
872 | int pin, bank, ret; |
873 | |
874 | ctrldesc->name = "samsung-pinctrl" ; |
875 | ctrldesc->owner = THIS_MODULE; |
876 | ctrldesc->pctlops = &samsung_pctrl_ops; |
877 | ctrldesc->pmxops = &samsung_pinmux_ops; |
878 | ctrldesc->confops = &samsung_pinconf_ops; |
879 | |
880 | pindesc = devm_kcalloc(dev: &pdev->dev, |
881 | n: drvdata->nr_pins, size: sizeof(*pindesc), |
882 | GFP_KERNEL); |
883 | if (!pindesc) |
884 | return -ENOMEM; |
885 | ctrldesc->pins = pindesc; |
886 | ctrldesc->npins = drvdata->nr_pins; |
887 | |
888 | /* dynamically populate the pin number and pin name for pindesc */ |
889 | for (pin = 0, pdesc = pindesc; pin < ctrldesc->npins; pin++, pdesc++) |
890 | pdesc->number = pin; |
891 | |
892 | /* |
893 | * allocate space for storing the dynamically generated names for all |
894 | * the pins which belong to this pin-controller. |
895 | */ |
896 | pin_names = devm_kzalloc(dev: &pdev->dev, |
897 | array3_size(sizeof(char), PIN_NAME_LENGTH, |
898 | drvdata->nr_pins), |
899 | GFP_KERNEL); |
900 | if (!pin_names) |
901 | return -ENOMEM; |
902 | |
903 | /* for each pin, the name of the pin is pin-bank name + pin number */ |
904 | for (bank = 0; bank < drvdata->nr_banks; bank++) { |
905 | pin_bank = &drvdata->pin_banks[bank]; |
906 | pin_bank->id = bank; |
907 | for (pin = 0; pin < pin_bank->nr_pins; pin++) { |
908 | sprintf(buf: pin_names, fmt: "%s-%d" , pin_bank->name, pin); |
909 | pdesc = pindesc + pin_bank->pin_base + pin; |
910 | pdesc->name = pin_names; |
911 | pin_names += PIN_NAME_LENGTH; |
912 | } |
913 | } |
914 | |
915 | ret = samsung_pinctrl_parse_dt(pdev, drvdata); |
916 | if (ret) |
917 | return ret; |
918 | |
919 | ret = devm_pinctrl_register_and_init(dev: &pdev->dev, pctldesc: ctrldesc, driver_data: drvdata, |
920 | pctldev: &drvdata->pctl_dev); |
921 | if (ret) { |
922 | dev_err(&pdev->dev, "could not register pinctrl driver\n" ); |
923 | return ret; |
924 | } |
925 | |
926 | return 0; |
927 | } |
928 | |
929 | /* unregister the pinctrl interface with the pinctrl subsystem */ |
930 | static int samsung_pinctrl_unregister(struct platform_device *pdev, |
931 | struct samsung_pinctrl_drv_data *drvdata) |
932 | { |
933 | struct samsung_pin_bank *bank = drvdata->pin_banks; |
934 | int i; |
935 | |
936 | for (i = 0; i < drvdata->nr_banks; ++i, ++bank) |
937 | pinctrl_remove_gpio_range(pctldev: drvdata->pctl_dev, range: &bank->grange); |
938 | |
939 | return 0; |
940 | } |
941 | |
942 | static const struct gpio_chip samsung_gpiolib_chip = { |
943 | .request = gpiochip_generic_request, |
944 | .free = gpiochip_generic_free, |
945 | .set = samsung_gpio_set, |
946 | .get = samsung_gpio_get, |
947 | .direction_input = samsung_gpio_direction_input, |
948 | .direction_output = samsung_gpio_direction_output, |
949 | .to_irq = samsung_gpio_to_irq, |
950 | .add_pin_ranges = samsung_add_pin_ranges, |
951 | .owner = THIS_MODULE, |
952 | }; |
953 | |
954 | /* register the gpiolib interface with the gpiolib subsystem */ |
955 | static int samsung_gpiolib_register(struct platform_device *pdev, |
956 | struct samsung_pinctrl_drv_data *drvdata) |
957 | { |
958 | struct samsung_pin_bank *bank = drvdata->pin_banks; |
959 | struct gpio_chip *gc; |
960 | int ret; |
961 | int i; |
962 | |
963 | for (i = 0; i < drvdata->nr_banks; ++i, ++bank) { |
964 | bank->gpio_chip = samsung_gpiolib_chip; |
965 | |
966 | gc = &bank->gpio_chip; |
967 | gc->base = -1; /* Dynamic allocation */ |
968 | gc->ngpio = bank->nr_pins; |
969 | gc->parent = &pdev->dev; |
970 | gc->fwnode = bank->fwnode; |
971 | gc->label = bank->name; |
972 | |
973 | ret = devm_gpiochip_add_data(&pdev->dev, gc, bank); |
974 | if (ret) { |
975 | dev_err(&pdev->dev, "failed to register gpio_chip %s, error code: %d\n" , |
976 | gc->label, ret); |
977 | return ret; |
978 | } |
979 | } |
980 | |
981 | return 0; |
982 | } |
983 | |
984 | static const struct samsung_pin_ctrl * |
985 | samsung_pinctrl_get_soc_data_for_of_alias(struct platform_device *pdev) |
986 | { |
987 | struct device_node *node = pdev->dev.of_node; |
988 | const struct samsung_pinctrl_of_match_data *of_data; |
989 | int id; |
990 | |
991 | id = of_alias_get_id(np: node, stem: "pinctrl" ); |
992 | if (id < 0) { |
993 | dev_err(&pdev->dev, "failed to get alias id\n" ); |
994 | return NULL; |
995 | } |
996 | |
997 | of_data = of_device_get_match_data(dev: &pdev->dev); |
998 | if (id >= of_data->num_ctrl) { |
999 | dev_err(&pdev->dev, "invalid alias id %d\n" , id); |
1000 | return NULL; |
1001 | } |
1002 | |
1003 | return &(of_data->ctrl[id]); |
1004 | } |
1005 | |
1006 | static void samsung_banks_node_put(struct samsung_pinctrl_drv_data *d) |
1007 | { |
1008 | struct samsung_pin_bank *bank; |
1009 | unsigned int i; |
1010 | |
1011 | bank = d->pin_banks; |
1012 | for (i = 0; i < d->nr_banks; ++i, ++bank) |
1013 | fwnode_handle_put(fwnode: bank->fwnode); |
1014 | } |
1015 | |
1016 | /* |
1017 | * Iterate over all driver pin banks to find one matching the name of node, |
1018 | * skipping optional "-gpio" node suffix. When found, assign node to the bank. |
1019 | */ |
1020 | static void samsung_banks_node_get(struct device *dev, struct samsung_pinctrl_drv_data *d) |
1021 | { |
1022 | const char *suffix = "-gpio-bank" ; |
1023 | struct samsung_pin_bank *bank; |
1024 | struct fwnode_handle *child; |
1025 | /* Pin bank names are up to 4 characters */ |
1026 | char node_name[20]; |
1027 | unsigned int i; |
1028 | size_t len; |
1029 | |
1030 | bank = d->pin_banks; |
1031 | for (i = 0; i < d->nr_banks; ++i, ++bank) { |
1032 | strscpy(node_name, bank->name, sizeof(node_name)); |
1033 | len = strlcat(p: node_name, q: suffix, avail: sizeof(node_name)); |
1034 | if (len >= sizeof(node_name)) { |
1035 | dev_err(dev, "Too long pin bank name '%s', ignoring\n" , |
1036 | bank->name); |
1037 | continue; |
1038 | } |
1039 | |
1040 | for_each_gpiochip_node(dev, child) { |
1041 | struct device_node *np = to_of_node(child); |
1042 | |
1043 | if (of_node_name_eq(np, name: node_name)) |
1044 | break; |
1045 | if (of_node_name_eq(np, name: bank->name)) |
1046 | break; |
1047 | } |
1048 | |
1049 | if (child) |
1050 | bank->fwnode = child; |
1051 | else |
1052 | dev_warn(dev, "Missing node for bank %s - invalid DTB\n" , |
1053 | bank->name); |
1054 | /* child reference dropped in samsung_drop_banks_of_node() */ |
1055 | } |
1056 | } |
1057 | |
1058 | /* retrieve the soc specific data */ |
1059 | static const struct samsung_pin_ctrl * |
1060 | samsung_pinctrl_get_soc_data(struct samsung_pinctrl_drv_data *d, |
1061 | struct platform_device *pdev) |
1062 | { |
1063 | const struct samsung_pin_bank_data *bdata; |
1064 | const struct samsung_pin_ctrl *ctrl; |
1065 | struct samsung_pin_bank *bank; |
1066 | struct resource *res; |
1067 | void __iomem *virt_base[SAMSUNG_PINCTRL_NUM_RESOURCES]; |
1068 | unsigned int i; |
1069 | |
1070 | ctrl = samsung_pinctrl_get_soc_data_for_of_alias(pdev); |
1071 | if (!ctrl) |
1072 | return ERR_PTR(error: -ENOENT); |
1073 | |
1074 | d->suspend = ctrl->suspend; |
1075 | d->resume = ctrl->resume; |
1076 | d->nr_banks = ctrl->nr_banks; |
1077 | d->pin_banks = devm_kcalloc(dev: &pdev->dev, n: d->nr_banks, |
1078 | size: sizeof(*d->pin_banks), GFP_KERNEL); |
1079 | if (!d->pin_banks) |
1080 | return ERR_PTR(error: -ENOMEM); |
1081 | |
1082 | if (ctrl->nr_ext_resources + 1 > SAMSUNG_PINCTRL_NUM_RESOURCES) |
1083 | return ERR_PTR(error: -EINVAL); |
1084 | |
1085 | for (i = 0; i < ctrl->nr_ext_resources + 1; i++) { |
1086 | res = platform_get_resource(pdev, IORESOURCE_MEM, i); |
1087 | if (!res) { |
1088 | dev_err(&pdev->dev, "failed to get mem%d resource\n" , i); |
1089 | return ERR_PTR(error: -EINVAL); |
1090 | } |
1091 | virt_base[i] = devm_ioremap(dev: &pdev->dev, offset: res->start, |
1092 | size: resource_size(res)); |
1093 | if (!virt_base[i]) { |
1094 | dev_err(&pdev->dev, "failed to ioremap %pR\n" , res); |
1095 | return ERR_PTR(error: -EIO); |
1096 | } |
1097 | } |
1098 | |
1099 | bank = d->pin_banks; |
1100 | bdata = ctrl->pin_banks; |
1101 | for (i = 0; i < ctrl->nr_banks; ++i, ++bdata, ++bank) { |
1102 | bank->type = bdata->type; |
1103 | bank->pctl_offset = bdata->pctl_offset; |
1104 | bank->nr_pins = bdata->nr_pins; |
1105 | bank->eint_func = bdata->eint_func; |
1106 | bank->eint_type = bdata->eint_type; |
1107 | bank->eint_mask = bdata->eint_mask; |
1108 | bank->eint_offset = bdata->eint_offset; |
1109 | bank->eint_con_offset = bdata->eint_con_offset; |
1110 | bank->eint_mask_offset = bdata->eint_mask_offset; |
1111 | bank->eint_pend_offset = bdata->eint_pend_offset; |
1112 | bank->name = bdata->name; |
1113 | |
1114 | raw_spin_lock_init(&bank->slock); |
1115 | bank->drvdata = d; |
1116 | bank->pin_base = d->nr_pins; |
1117 | d->nr_pins += bank->nr_pins; |
1118 | |
1119 | bank->eint_base = virt_base[0]; |
1120 | bank->pctl_base = virt_base[bdata->pctl_res_idx]; |
1121 | } |
1122 | /* |
1123 | * Legacy platforms should provide only one resource with IO memory. |
1124 | * Store it as virt_base because legacy driver needs to access it |
1125 | * through samsung_pinctrl_drv_data. |
1126 | */ |
1127 | d->virt_base = virt_base[0]; |
1128 | |
1129 | samsung_banks_node_get(dev: &pdev->dev, d); |
1130 | |
1131 | return ctrl; |
1132 | } |
1133 | |
1134 | static int samsung_pinctrl_probe(struct platform_device *pdev) |
1135 | { |
1136 | struct samsung_pinctrl_drv_data *drvdata; |
1137 | const struct samsung_pin_ctrl *ctrl; |
1138 | struct device *dev = &pdev->dev; |
1139 | int ret; |
1140 | |
1141 | drvdata = devm_kzalloc(dev, size: sizeof(*drvdata), GFP_KERNEL); |
1142 | if (!drvdata) |
1143 | return -ENOMEM; |
1144 | |
1145 | ctrl = samsung_pinctrl_get_soc_data(d: drvdata, pdev); |
1146 | if (IS_ERR(ptr: ctrl)) { |
1147 | dev_err(&pdev->dev, "driver data not available\n" ); |
1148 | return PTR_ERR(ptr: ctrl); |
1149 | } |
1150 | drvdata->dev = dev; |
1151 | |
1152 | ret = platform_get_irq_optional(pdev, 0); |
1153 | if (ret < 0 && ret != -ENXIO) |
1154 | return ret; |
1155 | if (ret > 0) |
1156 | drvdata->irq = ret; |
1157 | |
1158 | if (ctrl->retention_data) { |
1159 | drvdata->retention_ctrl = ctrl->retention_data->init(drvdata, |
1160 | ctrl->retention_data); |
1161 | if (IS_ERR(ptr: drvdata->retention_ctrl)) { |
1162 | ret = PTR_ERR(ptr: drvdata->retention_ctrl); |
1163 | goto err_put_banks; |
1164 | } |
1165 | } |
1166 | |
1167 | ret = samsung_pinctrl_register(pdev, drvdata); |
1168 | if (ret) |
1169 | goto err_put_banks; |
1170 | |
1171 | if (ctrl->eint_gpio_init) |
1172 | ctrl->eint_gpio_init(drvdata); |
1173 | if (ctrl->eint_wkup_init) |
1174 | ctrl->eint_wkup_init(drvdata); |
1175 | |
1176 | ret = samsung_gpiolib_register(pdev, drvdata); |
1177 | if (ret) |
1178 | goto err_unregister; |
1179 | |
1180 | ret = pinctrl_enable(pctldev: drvdata->pctl_dev); |
1181 | if (ret) |
1182 | goto err_unregister; |
1183 | |
1184 | platform_set_drvdata(pdev, data: drvdata); |
1185 | |
1186 | return 0; |
1187 | |
1188 | err_unregister: |
1189 | samsung_pinctrl_unregister(pdev, drvdata); |
1190 | err_put_banks: |
1191 | samsung_banks_node_put(d: drvdata); |
1192 | return ret; |
1193 | } |
1194 | |
1195 | /* |
1196 | * samsung_pinctrl_suspend - save pinctrl state for suspend |
1197 | * |
1198 | * Save data for all banks handled by this device. |
1199 | */ |
1200 | static int __maybe_unused samsung_pinctrl_suspend(struct device *dev) |
1201 | { |
1202 | struct samsung_pinctrl_drv_data *drvdata = dev_get_drvdata(dev); |
1203 | int i; |
1204 | |
1205 | for (i = 0; i < drvdata->nr_banks; i++) { |
1206 | struct samsung_pin_bank *bank = &drvdata->pin_banks[i]; |
1207 | const void __iomem *reg = bank->pctl_base + bank->pctl_offset; |
1208 | const u8 *offs = bank->type->reg_offset; |
1209 | const u8 *widths = bank->type->fld_width; |
1210 | enum pincfg_type type; |
1211 | |
1212 | /* Registers without a powerdown config aren't lost */ |
1213 | if (!widths[PINCFG_TYPE_CON_PDN]) |
1214 | continue; |
1215 | |
1216 | for (type = 0; type < PINCFG_TYPE_NUM; type++) |
1217 | if (widths[type]) |
1218 | bank->pm_save[type] = readl(addr: reg + offs[type]); |
1219 | |
1220 | if (widths[PINCFG_TYPE_FUNC] * bank->nr_pins > 32) { |
1221 | /* Some banks have two config registers */ |
1222 | bank->pm_save[PINCFG_TYPE_NUM] = |
1223 | readl(addr: reg + offs[PINCFG_TYPE_FUNC] + 4); |
1224 | pr_debug("Save %s @ %p (con %#010x %08x)\n" , |
1225 | bank->name, reg, |
1226 | bank->pm_save[PINCFG_TYPE_FUNC], |
1227 | bank->pm_save[PINCFG_TYPE_NUM]); |
1228 | } else { |
1229 | pr_debug("Save %s @ %p (con %#010x)\n" , bank->name, |
1230 | reg, bank->pm_save[PINCFG_TYPE_FUNC]); |
1231 | } |
1232 | } |
1233 | |
1234 | if (drvdata->suspend) |
1235 | drvdata->suspend(drvdata); |
1236 | if (drvdata->retention_ctrl && drvdata->retention_ctrl->enable) |
1237 | drvdata->retention_ctrl->enable(drvdata); |
1238 | |
1239 | return 0; |
1240 | } |
1241 | |
1242 | /* |
1243 | * samsung_pinctrl_resume - restore pinctrl state from suspend |
1244 | * |
1245 | * Restore one of the banks that was saved during suspend. |
1246 | * |
1247 | * We don't bother doing anything complicated to avoid glitching lines since |
1248 | * we're called before pad retention is turned off. |
1249 | */ |
1250 | static int __maybe_unused samsung_pinctrl_resume(struct device *dev) |
1251 | { |
1252 | struct samsung_pinctrl_drv_data *drvdata = dev_get_drvdata(dev); |
1253 | int i; |
1254 | |
1255 | if (drvdata->resume) |
1256 | drvdata->resume(drvdata); |
1257 | |
1258 | for (i = 0; i < drvdata->nr_banks; i++) { |
1259 | struct samsung_pin_bank *bank = &drvdata->pin_banks[i]; |
1260 | void __iomem *reg = bank->pctl_base + bank->pctl_offset; |
1261 | const u8 *offs = bank->type->reg_offset; |
1262 | const u8 *widths = bank->type->fld_width; |
1263 | enum pincfg_type type; |
1264 | |
1265 | /* Registers without a powerdown config aren't lost */ |
1266 | if (!widths[PINCFG_TYPE_CON_PDN]) |
1267 | continue; |
1268 | |
1269 | if (widths[PINCFG_TYPE_FUNC] * bank->nr_pins > 32) { |
1270 | /* Some banks have two config registers */ |
1271 | pr_debug("%s @ %p (con %#010x %08x => %#010x %08x)\n" , |
1272 | bank->name, reg, |
1273 | readl(reg + offs[PINCFG_TYPE_FUNC]), |
1274 | readl(reg + offs[PINCFG_TYPE_FUNC] + 4), |
1275 | bank->pm_save[PINCFG_TYPE_FUNC], |
1276 | bank->pm_save[PINCFG_TYPE_NUM]); |
1277 | writel(val: bank->pm_save[PINCFG_TYPE_NUM], |
1278 | addr: reg + offs[PINCFG_TYPE_FUNC] + 4); |
1279 | } else { |
1280 | pr_debug("%s @ %p (con %#010x => %#010x)\n" , bank->name, |
1281 | reg, readl(reg + offs[PINCFG_TYPE_FUNC]), |
1282 | bank->pm_save[PINCFG_TYPE_FUNC]); |
1283 | } |
1284 | for (type = 0; type < PINCFG_TYPE_NUM; type++) |
1285 | if (widths[type]) |
1286 | writel(val: bank->pm_save[type], addr: reg + offs[type]); |
1287 | } |
1288 | |
1289 | if (drvdata->retention_ctrl && drvdata->retention_ctrl->disable) |
1290 | drvdata->retention_ctrl->disable(drvdata); |
1291 | |
1292 | return 0; |
1293 | } |
1294 | |
1295 | static const struct of_device_id samsung_pinctrl_dt_match[] = { |
1296 | #ifdef CONFIG_PINCTRL_EXYNOS_ARM |
1297 | { .compatible = "samsung,exynos3250-pinctrl" , |
1298 | .data = &exynos3250_of_data }, |
1299 | { .compatible = "samsung,exynos4210-pinctrl" , |
1300 | .data = &exynos4210_of_data }, |
1301 | { .compatible = "samsung,exynos4x12-pinctrl" , |
1302 | .data = &exynos4x12_of_data }, |
1303 | { .compatible = "samsung,exynos5250-pinctrl" , |
1304 | .data = &exynos5250_of_data }, |
1305 | { .compatible = "samsung,exynos5260-pinctrl" , |
1306 | .data = &exynos5260_of_data }, |
1307 | { .compatible = "samsung,exynos5410-pinctrl" , |
1308 | .data = &exynos5410_of_data }, |
1309 | { .compatible = "samsung,exynos5420-pinctrl" , |
1310 | .data = &exynos5420_of_data }, |
1311 | { .compatible = "samsung,s5pv210-pinctrl" , |
1312 | .data = &s5pv210_of_data }, |
1313 | #endif |
1314 | #ifdef CONFIG_PINCTRL_EXYNOS_ARM64 |
1315 | { .compatible = "google,gs101-pinctrl" , |
1316 | .data = &gs101_of_data }, |
1317 | { .compatible = "samsung,exynos5433-pinctrl" , |
1318 | .data = &exynos5433_of_data }, |
1319 | { .compatible = "samsung,exynos7-pinctrl" , |
1320 | .data = &exynos7_of_data }, |
1321 | { .compatible = "samsung,exynos7885-pinctrl" , |
1322 | .data = &exynos7885_of_data }, |
1323 | { .compatible = "samsung,exynos850-pinctrl" , |
1324 | .data = &exynos850_of_data }, |
1325 | { .compatible = "samsung,exynosautov9-pinctrl" , |
1326 | .data = &exynosautov9_of_data }, |
1327 | { .compatible = "samsung,exynosautov920-pinctrl" , |
1328 | .data = &exynosautov920_of_data }, |
1329 | { .compatible = "tesla,fsd-pinctrl" , |
1330 | .data = &fsd_of_data }, |
1331 | #endif |
1332 | #ifdef CONFIG_PINCTRL_S3C64XX |
1333 | { .compatible = "samsung,s3c64xx-pinctrl" , |
1334 | .data = &s3c64xx_of_data }, |
1335 | #endif |
1336 | {}, |
1337 | }; |
1338 | |
1339 | static const struct dev_pm_ops samsung_pinctrl_pm_ops = { |
1340 | SET_LATE_SYSTEM_SLEEP_PM_OPS(samsung_pinctrl_suspend, |
1341 | samsung_pinctrl_resume) |
1342 | }; |
1343 | |
1344 | static struct platform_driver samsung_pinctrl_driver = { |
1345 | .probe = samsung_pinctrl_probe, |
1346 | .driver = { |
1347 | .name = "samsung-pinctrl" , |
1348 | .of_match_table = samsung_pinctrl_dt_match, |
1349 | .suppress_bind_attrs = true, |
1350 | .pm = &samsung_pinctrl_pm_ops, |
1351 | }, |
1352 | }; |
1353 | |
1354 | static int __init samsung_pinctrl_drv_register(void) |
1355 | { |
1356 | return platform_driver_register(&samsung_pinctrl_driver); |
1357 | } |
1358 | postcore_initcall(samsung_pinctrl_drv_register); |
1359 | |