diff options
Diffstat (limited to 'drivers/pinctrl/pinctrl-samsung.c')
-rw-r--r-- | drivers/pinctrl/pinctrl-samsung.c | 1181 |
1 files changed, 0 insertions, 1181 deletions
diff --git a/drivers/pinctrl/pinctrl-samsung.c b/drivers/pinctrl/pinctrl-samsung.c deleted file mode 100644 index 3e61d0f8f146..000000000000 --- a/drivers/pinctrl/pinctrl-samsung.c +++ /dev/null | |||
@@ -1,1181 +0,0 @@ | |||
1 | /* | ||
2 | * pin-controller/pin-mux/pin-config/gpio-driver for Samsung's SoC's. | ||
3 | * | ||
4 | * Copyright (c) 2012 Samsung Electronics Co., Ltd. | ||
5 | * http://www.samsung.com | ||
6 | * Copyright (c) 2012 Linaro Ltd | ||
7 | * http://www.linaro.org | ||
8 | * | ||
9 | * Author: Thomas Abraham <thomas.ab@samsung.com> | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | ||
12 | * it under the terms of the GNU General Public License as published by | ||
13 | * the Free Software Foundation; either version 2 of the License, or | ||
14 | * (at your option) any later version. | ||
15 | * | ||
16 | * This driver implements the Samsung pinctrl driver. It supports setting up of | ||
17 | * pinmux and pinconf configurations. The gpiolib interface is also included. | ||
18 | * External interrupt (gpio and wakeup) support are not included in this driver | ||
19 | * but provides extensions to which platform specific implementation of the gpio | ||
20 | * and wakeup interrupts can be hooked to. | ||
21 | */ | ||
22 | |||
23 | #include <linux/module.h> | ||
24 | #include <linux/platform_device.h> | ||
25 | #include <linux/io.h> | ||
26 | #include <linux/slab.h> | ||
27 | #include <linux/err.h> | ||
28 | #include <linux/gpio.h> | ||
29 | #include <linux/irqdomain.h> | ||
30 | #include <linux/spinlock.h> | ||
31 | #include <linux/syscore_ops.h> | ||
32 | |||
33 | #include "core.h" | ||
34 | #include "pinctrl-samsung.h" | ||
35 | |||
36 | #define GROUP_SUFFIX "-grp" | ||
37 | #define GSUFFIX_LEN sizeof(GROUP_SUFFIX) | ||
38 | #define FUNCTION_SUFFIX "-mux" | ||
39 | #define FSUFFIX_LEN sizeof(FUNCTION_SUFFIX) | ||
40 | |||
41 | /* list of all possible config options supported */ | ||
42 | static struct pin_config { | ||
43 | char *prop_cfg; | ||
44 | unsigned int cfg_type; | ||
45 | } pcfgs[] = { | ||
46 | { "samsung,pin-pud", PINCFG_TYPE_PUD }, | ||
47 | { "samsung,pin-drv", PINCFG_TYPE_DRV }, | ||
48 | { "samsung,pin-con-pdn", PINCFG_TYPE_CON_PDN }, | ||
49 | { "samsung,pin-pud-pdn", PINCFG_TYPE_PUD_PDN }, | ||
50 | }; | ||
51 | |||
52 | /* Global list of devices (struct samsung_pinctrl_drv_data) */ | ||
53 | static LIST_HEAD(drvdata_list); | ||
54 | |||
55 | static unsigned int pin_base; | ||
56 | |||
57 | static inline struct samsung_pin_bank *gc_to_pin_bank(struct gpio_chip *gc) | ||
58 | { | ||
59 | return container_of(gc, struct samsung_pin_bank, gpio_chip); | ||
60 | } | ||
61 | |||
62 | /* check if the selector is a valid pin group selector */ | ||
63 | static int samsung_get_group_count(struct pinctrl_dev *pctldev) | ||
64 | { | ||
65 | struct samsung_pinctrl_drv_data *drvdata; | ||
66 | |||
67 | drvdata = pinctrl_dev_get_drvdata(pctldev); | ||
68 | return drvdata->nr_groups; | ||
69 | } | ||
70 | |||
71 | /* return the name of the group selected by the group selector */ | ||
72 | static const char *samsung_get_group_name(struct pinctrl_dev *pctldev, | ||
73 | unsigned selector) | ||
74 | { | ||
75 | struct samsung_pinctrl_drv_data *drvdata; | ||
76 | |||
77 | drvdata = pinctrl_dev_get_drvdata(pctldev); | ||
78 | return drvdata->pin_groups[selector].name; | ||
79 | } | ||
80 | |||
81 | /* return the pin numbers associated with the specified group */ | ||
82 | static int samsung_get_group_pins(struct pinctrl_dev *pctldev, | ||
83 | unsigned selector, const unsigned **pins, unsigned *num_pins) | ||
84 | { | ||
85 | struct samsung_pinctrl_drv_data *drvdata; | ||
86 | |||
87 | drvdata = pinctrl_dev_get_drvdata(pctldev); | ||
88 | *pins = drvdata->pin_groups[selector].pins; | ||
89 | *num_pins = drvdata->pin_groups[selector].num_pins; | ||
90 | return 0; | ||
91 | } | ||
92 | |||
93 | /* create pinctrl_map entries by parsing device tree nodes */ | ||
94 | static int samsung_dt_node_to_map(struct pinctrl_dev *pctldev, | ||
95 | struct device_node *np, struct pinctrl_map **maps, | ||
96 | unsigned *nmaps) | ||
97 | { | ||
98 | struct device *dev = pctldev->dev; | ||
99 | struct pinctrl_map *map; | ||
100 | unsigned long *cfg = NULL; | ||
101 | char *gname, *fname; | ||
102 | int cfg_cnt = 0, map_cnt = 0, idx = 0; | ||
103 | |||
104 | /* count the number of config options specfied in the node */ | ||
105 | for (idx = 0; idx < ARRAY_SIZE(pcfgs); idx++) { | ||
106 | if (of_find_property(np, pcfgs[idx].prop_cfg, NULL)) | ||
107 | cfg_cnt++; | ||
108 | } | ||
109 | |||
110 | /* | ||
111 | * Find out the number of map entries to create. All the config options | ||
112 | * can be accomadated into a single config map entry. | ||
113 | */ | ||
114 | if (cfg_cnt) | ||
115 | map_cnt = 1; | ||
116 | if (of_find_property(np, "samsung,pin-function", NULL)) | ||
117 | map_cnt++; | ||
118 | if (!map_cnt) { | ||
119 | dev_err(dev, "node %s does not have either config or function " | ||
120 | "configurations\n", np->name); | ||
121 | return -EINVAL; | ||
122 | } | ||
123 | |||
124 | /* Allocate memory for pin-map entries */ | ||
125 | map = kzalloc(sizeof(*map) * map_cnt, GFP_KERNEL); | ||
126 | if (!map) { | ||
127 | dev_err(dev, "could not alloc memory for pin-maps\n"); | ||
128 | return -ENOMEM; | ||
129 | } | ||
130 | *nmaps = 0; | ||
131 | |||
132 | /* | ||
133 | * Allocate memory for pin group name. The pin group name is derived | ||
134 | * from the node name from which these map entries are be created. | ||
135 | */ | ||
136 | gname = kzalloc(strlen(np->name) + GSUFFIX_LEN, GFP_KERNEL); | ||
137 | if (!gname) { | ||
138 | dev_err(dev, "failed to alloc memory for group name\n"); | ||
139 | goto free_map; | ||
140 | } | ||
141 | sprintf(gname, "%s%s", np->name, GROUP_SUFFIX); | ||
142 | |||
143 | /* | ||
144 | * don't have config options? then skip over to creating function | ||
145 | * map entries. | ||
146 | */ | ||
147 | if (!cfg_cnt) | ||
148 | goto skip_cfgs; | ||
149 | |||
150 | /* Allocate memory for config entries */ | ||
151 | cfg = kzalloc(sizeof(*cfg) * cfg_cnt, GFP_KERNEL); | ||
152 | if (!cfg) { | ||
153 | dev_err(dev, "failed to alloc memory for configs\n"); | ||
154 | goto free_gname; | ||
155 | } | ||
156 | |||
157 | /* Prepare a list of config settings */ | ||
158 | for (idx = 0, cfg_cnt = 0; idx < ARRAY_SIZE(pcfgs); idx++) { | ||
159 | u32 value; | ||
160 | if (!of_property_read_u32(np, pcfgs[idx].prop_cfg, &value)) | ||
161 | cfg[cfg_cnt++] = | ||
162 | PINCFG_PACK(pcfgs[idx].cfg_type, value); | ||
163 | } | ||
164 | |||
165 | /* create the config map entry */ | ||
166 | map[*nmaps].data.configs.group_or_pin = gname; | ||
167 | map[*nmaps].data.configs.configs = cfg; | ||
168 | map[*nmaps].data.configs.num_configs = cfg_cnt; | ||
169 | map[*nmaps].type = PIN_MAP_TYPE_CONFIGS_GROUP; | ||
170 | *nmaps += 1; | ||
171 | |||
172 | skip_cfgs: | ||
173 | /* create the function map entry */ | ||
174 | if (of_find_property(np, "samsung,pin-function", NULL)) { | ||
175 | fname = kzalloc(strlen(np->name) + FSUFFIX_LEN, GFP_KERNEL); | ||
176 | if (!fname) { | ||
177 | dev_err(dev, "failed to alloc memory for func name\n"); | ||
178 | goto free_cfg; | ||
179 | } | ||
180 | sprintf(fname, "%s%s", np->name, FUNCTION_SUFFIX); | ||
181 | |||
182 | map[*nmaps].data.mux.group = gname; | ||
183 | map[*nmaps].data.mux.function = fname; | ||
184 | map[*nmaps].type = PIN_MAP_TYPE_MUX_GROUP; | ||
185 | *nmaps += 1; | ||
186 | } | ||
187 | |||
188 | *maps = map; | ||
189 | return 0; | ||
190 | |||
191 | free_cfg: | ||
192 | kfree(cfg); | ||
193 | free_gname: | ||
194 | kfree(gname); | ||
195 | free_map: | ||
196 | kfree(map); | ||
197 | return -ENOMEM; | ||
198 | } | ||
199 | |||
200 | /* free the memory allocated to hold the pin-map table */ | ||
201 | static void samsung_dt_free_map(struct pinctrl_dev *pctldev, | ||
202 | struct pinctrl_map *map, unsigned num_maps) | ||
203 | { | ||
204 | int idx; | ||
205 | |||
206 | for (idx = 0; idx < num_maps; idx++) { | ||
207 | if (map[idx].type == PIN_MAP_TYPE_MUX_GROUP) { | ||
208 | kfree(map[idx].data.mux.function); | ||
209 | if (!idx) | ||
210 | kfree(map[idx].data.mux.group); | ||
211 | } else if (map->type == PIN_MAP_TYPE_CONFIGS_GROUP) { | ||
212 | kfree(map[idx].data.configs.configs); | ||
213 | if (!idx) | ||
214 | kfree(map[idx].data.configs.group_or_pin); | ||
215 | } | ||
216 | }; | ||
217 | |||
218 | kfree(map); | ||
219 | } | ||
220 | |||
221 | /* list of pinctrl callbacks for the pinctrl core */ | ||
222 | static const struct pinctrl_ops samsung_pctrl_ops = { | ||
223 | .get_groups_count = samsung_get_group_count, | ||
224 | .get_group_name = samsung_get_group_name, | ||
225 | .get_group_pins = samsung_get_group_pins, | ||
226 | .dt_node_to_map = samsung_dt_node_to_map, | ||
227 | .dt_free_map = samsung_dt_free_map, | ||
228 | }; | ||
229 | |||
230 | /* check if the selector is a valid pin function selector */ | ||
231 | static int samsung_get_functions_count(struct pinctrl_dev *pctldev) | ||
232 | { | ||
233 | struct samsung_pinctrl_drv_data *drvdata; | ||
234 | |||
235 | drvdata = pinctrl_dev_get_drvdata(pctldev); | ||
236 | return drvdata->nr_functions; | ||
237 | } | ||
238 | |||
239 | /* return the name of the pin function specified */ | ||
240 | static const char *samsung_pinmux_get_fname(struct pinctrl_dev *pctldev, | ||
241 | unsigned selector) | ||
242 | { | ||
243 | struct samsung_pinctrl_drv_data *drvdata; | ||
244 | |||
245 | drvdata = pinctrl_dev_get_drvdata(pctldev); | ||
246 | return drvdata->pmx_functions[selector].name; | ||
247 | } | ||
248 | |||
249 | /* return the groups associated for the specified function selector */ | ||
250 | static int samsung_pinmux_get_groups(struct pinctrl_dev *pctldev, | ||
251 | unsigned selector, const char * const **groups, | ||
252 | unsigned * const num_groups) | ||
253 | { | ||
254 | struct samsung_pinctrl_drv_data *drvdata; | ||
255 | |||
256 | drvdata = pinctrl_dev_get_drvdata(pctldev); | ||
257 | *groups = drvdata->pmx_functions[selector].groups; | ||
258 | *num_groups = drvdata->pmx_functions[selector].num_groups; | ||
259 | return 0; | ||
260 | } | ||
261 | |||
262 | /* | ||
263 | * given a pin number that is local to a pin controller, find out the pin bank | ||
264 | * and the register base of the pin bank. | ||
265 | */ | ||
266 | static void pin_to_reg_bank(struct samsung_pinctrl_drv_data *drvdata, | ||
267 | unsigned pin, void __iomem **reg, u32 *offset, | ||
268 | struct samsung_pin_bank **bank) | ||
269 | { | ||
270 | struct samsung_pin_bank *b; | ||
271 | |||
272 | b = drvdata->ctrl->pin_banks; | ||
273 | |||
274 | while ((pin >= b->pin_base) && | ||
275 | ((b->pin_base + b->nr_pins - 1) < pin)) | ||
276 | b++; | ||
277 | |||
278 | *reg = drvdata->virt_base + b->pctl_offset; | ||
279 | *offset = pin - b->pin_base; | ||
280 | if (bank) | ||
281 | *bank = b; | ||
282 | } | ||
283 | |||
284 | /* enable or disable a pinmux function */ | ||
285 | static void samsung_pinmux_setup(struct pinctrl_dev *pctldev, unsigned selector, | ||
286 | unsigned group, bool enable) | ||
287 | { | ||
288 | struct samsung_pinctrl_drv_data *drvdata; | ||
289 | const unsigned int *pins; | ||
290 | struct samsung_pin_bank *bank; | ||
291 | void __iomem *reg; | ||
292 | u32 mask, shift, data, pin_offset, cnt; | ||
293 | unsigned long flags; | ||
294 | |||
295 | drvdata = pinctrl_dev_get_drvdata(pctldev); | ||
296 | pins = drvdata->pin_groups[group].pins; | ||
297 | |||
298 | /* | ||
299 | * for each pin in the pin group selected, program the correspoding pin | ||
300 | * pin function number in the config register. | ||
301 | */ | ||
302 | for (cnt = 0; cnt < drvdata->pin_groups[group].num_pins; cnt++) { | ||
303 | struct samsung_pin_bank_type *type; | ||
304 | |||
305 | pin_to_reg_bank(drvdata, pins[cnt] - drvdata->ctrl->base, | ||
306 | ®, &pin_offset, &bank); | ||
307 | type = bank->type; | ||
308 | mask = (1 << type->fld_width[PINCFG_TYPE_FUNC]) - 1; | ||
309 | shift = pin_offset * type->fld_width[PINCFG_TYPE_FUNC]; | ||
310 | if (shift >= 32) { | ||
311 | /* Some banks have two config registers */ | ||
312 | shift -= 32; | ||
313 | reg += 4; | ||
314 | } | ||
315 | |||
316 | spin_lock_irqsave(&bank->slock, flags); | ||
317 | |||
318 | data = readl(reg + type->reg_offset[PINCFG_TYPE_FUNC]); | ||
319 | data &= ~(mask << shift); | ||
320 | if (enable) | ||
321 | data |= drvdata->pin_groups[group].func << shift; | ||
322 | writel(data, reg + type->reg_offset[PINCFG_TYPE_FUNC]); | ||
323 | |||
324 | spin_unlock_irqrestore(&bank->slock, flags); | ||
325 | } | ||
326 | } | ||
327 | |||
328 | /* enable a specified pinmux by writing to registers */ | ||
329 | static int samsung_pinmux_enable(struct pinctrl_dev *pctldev, unsigned selector, | ||
330 | unsigned group) | ||
331 | { | ||
332 | samsung_pinmux_setup(pctldev, selector, group, true); | ||
333 | return 0; | ||
334 | } | ||
335 | |||
336 | /* disable a specified pinmux by writing to registers */ | ||
337 | static void samsung_pinmux_disable(struct pinctrl_dev *pctldev, | ||
338 | unsigned selector, unsigned group) | ||
339 | { | ||
340 | samsung_pinmux_setup(pctldev, selector, group, false); | ||
341 | } | ||
342 | |||
343 | /* | ||
344 | * The calls to gpio_direction_output() and gpio_direction_input() | ||
345 | * leads to this function call (via the pinctrl_gpio_direction_{input|output}() | ||
346 | * function called from the gpiolib interface). | ||
347 | */ | ||
348 | static int samsung_pinmux_gpio_set_direction(struct pinctrl_dev *pctldev, | ||
349 | struct pinctrl_gpio_range *range, unsigned offset, bool input) | ||
350 | { | ||
351 | struct samsung_pin_bank_type *type; | ||
352 | struct samsung_pin_bank *bank; | ||
353 | struct samsung_pinctrl_drv_data *drvdata; | ||
354 | void __iomem *reg; | ||
355 | u32 data, pin_offset, mask, shift; | ||
356 | unsigned long flags; | ||
357 | |||
358 | bank = gc_to_pin_bank(range->gc); | ||
359 | type = bank->type; | ||
360 | drvdata = pinctrl_dev_get_drvdata(pctldev); | ||
361 | |||
362 | pin_offset = offset - bank->pin_base; | ||
363 | reg = drvdata->virt_base + bank->pctl_offset + | ||
364 | type->reg_offset[PINCFG_TYPE_FUNC]; | ||
365 | |||
366 | mask = (1 << type->fld_width[PINCFG_TYPE_FUNC]) - 1; | ||
367 | shift = pin_offset * type->fld_width[PINCFG_TYPE_FUNC]; | ||
368 | if (shift >= 32) { | ||
369 | /* Some banks have two config registers */ | ||
370 | shift -= 32; | ||
371 | reg += 4; | ||
372 | } | ||
373 | |||
374 | spin_lock_irqsave(&bank->slock, flags); | ||
375 | |||
376 | data = readl(reg); | ||
377 | data &= ~(mask << shift); | ||
378 | if (!input) | ||
379 | data |= FUNC_OUTPUT << shift; | ||
380 | writel(data, reg); | ||
381 | |||
382 | spin_unlock_irqrestore(&bank->slock, flags); | ||
383 | |||
384 | return 0; | ||
385 | } | ||
386 | |||
387 | /* list of pinmux callbacks for the pinmux vertical in pinctrl core */ | ||
388 | static const struct pinmux_ops samsung_pinmux_ops = { | ||
389 | .get_functions_count = samsung_get_functions_count, | ||
390 | .get_function_name = samsung_pinmux_get_fname, | ||
391 | .get_function_groups = samsung_pinmux_get_groups, | ||
392 | .enable = samsung_pinmux_enable, | ||
393 | .disable = samsung_pinmux_disable, | ||
394 | .gpio_set_direction = samsung_pinmux_gpio_set_direction, | ||
395 | }; | ||
396 | |||
397 | /* set or get the pin config settings for a specified pin */ | ||
398 | static int samsung_pinconf_rw(struct pinctrl_dev *pctldev, unsigned int pin, | ||
399 | unsigned long *config, bool set) | ||
400 | { | ||
401 | struct samsung_pinctrl_drv_data *drvdata; | ||
402 | struct samsung_pin_bank_type *type; | ||
403 | struct samsung_pin_bank *bank; | ||
404 | void __iomem *reg_base; | ||
405 | enum pincfg_type cfg_type = PINCFG_UNPACK_TYPE(*config); | ||
406 | u32 data, width, pin_offset, mask, shift; | ||
407 | u32 cfg_value, cfg_reg; | ||
408 | unsigned long flags; | ||
409 | |||
410 | drvdata = pinctrl_dev_get_drvdata(pctldev); | ||
411 | pin_to_reg_bank(drvdata, pin - drvdata->ctrl->base, ®_base, | ||
412 | &pin_offset, &bank); | ||
413 | type = bank->type; | ||
414 | |||
415 | if (cfg_type >= PINCFG_TYPE_NUM || !type->fld_width[cfg_type]) | ||
416 | return -EINVAL; | ||
417 | |||
418 | width = type->fld_width[cfg_type]; | ||
419 | cfg_reg = type->reg_offset[cfg_type]; | ||
420 | |||
421 | spin_lock_irqsave(&bank->slock, flags); | ||
422 | |||
423 | mask = (1 << width) - 1; | ||
424 | shift = pin_offset * width; | ||
425 | data = readl(reg_base + cfg_reg); | ||
426 | |||
427 | if (set) { | ||
428 | cfg_value = PINCFG_UNPACK_VALUE(*config); | ||
429 | data &= ~(mask << shift); | ||
430 | data |= (cfg_value << shift); | ||
431 | writel(data, reg_base + cfg_reg); | ||
432 | } else { | ||
433 | data >>= shift; | ||
434 | data &= mask; | ||
435 | *config = PINCFG_PACK(cfg_type, data); | ||
436 | } | ||
437 | |||
438 | spin_unlock_irqrestore(&bank->slock, flags); | ||
439 | |||
440 | return 0; | ||
441 | } | ||
442 | |||
443 | /* set the pin config settings for a specified pin */ | ||
444 | static int samsung_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin, | ||
445 | unsigned long *configs, unsigned num_configs) | ||
446 | { | ||
447 | int i, ret; | ||
448 | |||
449 | for (i = 0; i < num_configs; i++) { | ||
450 | ret = samsung_pinconf_rw(pctldev, pin, &configs[i], true); | ||
451 | if (ret < 0) | ||
452 | return ret; | ||
453 | } /* for each config */ | ||
454 | |||
455 | return 0; | ||
456 | } | ||
457 | |||
458 | /* get the pin config settings for a specified pin */ | ||
459 | static int samsung_pinconf_get(struct pinctrl_dev *pctldev, unsigned int pin, | ||
460 | unsigned long *config) | ||
461 | { | ||
462 | return samsung_pinconf_rw(pctldev, pin, config, false); | ||
463 | } | ||
464 | |||
465 | /* set the pin config settings for a specified pin group */ | ||
466 | static int samsung_pinconf_group_set(struct pinctrl_dev *pctldev, | ||
467 | unsigned group, unsigned long *configs, | ||
468 | unsigned num_configs) | ||
469 | { | ||
470 | struct samsung_pinctrl_drv_data *drvdata; | ||
471 | const unsigned int *pins; | ||
472 | unsigned int cnt; | ||
473 | |||
474 | drvdata = pinctrl_dev_get_drvdata(pctldev); | ||
475 | pins = drvdata->pin_groups[group].pins; | ||
476 | |||
477 | for (cnt = 0; cnt < drvdata->pin_groups[group].num_pins; cnt++) | ||
478 | samsung_pinconf_set(pctldev, pins[cnt], configs, num_configs); | ||
479 | |||
480 | return 0; | ||
481 | } | ||
482 | |||
483 | /* get the pin config settings for a specified pin group */ | ||
484 | static int samsung_pinconf_group_get(struct pinctrl_dev *pctldev, | ||
485 | unsigned int group, unsigned long *config) | ||
486 | { | ||
487 | struct samsung_pinctrl_drv_data *drvdata; | ||
488 | const unsigned int *pins; | ||
489 | |||
490 | drvdata = pinctrl_dev_get_drvdata(pctldev); | ||
491 | pins = drvdata->pin_groups[group].pins; | ||
492 | samsung_pinconf_get(pctldev, pins[0], config); | ||
493 | return 0; | ||
494 | } | ||
495 | |||
496 | /* list of pinconfig callbacks for pinconfig vertical in the pinctrl code */ | ||
497 | static const struct pinconf_ops samsung_pinconf_ops = { | ||
498 | .pin_config_get = samsung_pinconf_get, | ||
499 | .pin_config_set = samsung_pinconf_set, | ||
500 | .pin_config_group_get = samsung_pinconf_group_get, | ||
501 | .pin_config_group_set = samsung_pinconf_group_set, | ||
502 | }; | ||
503 | |||
504 | /* gpiolib gpio_set callback function */ | ||
505 | static void samsung_gpio_set(struct gpio_chip *gc, unsigned offset, int value) | ||
506 | { | ||
507 | struct samsung_pin_bank *bank = gc_to_pin_bank(gc); | ||
508 | struct samsung_pin_bank_type *type = bank->type; | ||
509 | unsigned long flags; | ||
510 | void __iomem *reg; | ||
511 | u32 data; | ||
512 | |||
513 | reg = bank->drvdata->virt_base + bank->pctl_offset; | ||
514 | |||
515 | spin_lock_irqsave(&bank->slock, flags); | ||
516 | |||
517 | data = readl(reg + type->reg_offset[PINCFG_TYPE_DAT]); | ||
518 | data &= ~(1 << offset); | ||
519 | if (value) | ||
520 | data |= 1 << offset; | ||
521 | writel(data, reg + type->reg_offset[PINCFG_TYPE_DAT]); | ||
522 | |||
523 | spin_unlock_irqrestore(&bank->slock, flags); | ||
524 | } | ||
525 | |||
526 | /* gpiolib gpio_get callback function */ | ||
527 | static int samsung_gpio_get(struct gpio_chip *gc, unsigned offset) | ||
528 | { | ||
529 | void __iomem *reg; | ||
530 | u32 data; | ||
531 | struct samsung_pin_bank *bank = gc_to_pin_bank(gc); | ||
532 | struct samsung_pin_bank_type *type = bank->type; | ||
533 | |||
534 | reg = bank->drvdata->virt_base + bank->pctl_offset; | ||
535 | |||
536 | data = readl(reg + type->reg_offset[PINCFG_TYPE_DAT]); | ||
537 | data >>= offset; | ||
538 | data &= 1; | ||
539 | return data; | ||
540 | } | ||
541 | |||
542 | /* | ||
543 | * gpiolib gpio_direction_input callback function. The setting of the pin | ||
544 | * mux function as 'gpio input' will be handled by the pinctrl susbsystem | ||
545 | * interface. | ||
546 | */ | ||
547 | static int samsung_gpio_direction_input(struct gpio_chip *gc, unsigned offset) | ||
548 | { | ||
549 | return pinctrl_gpio_direction_input(gc->base + offset); | ||
550 | } | ||
551 | |||
552 | /* | ||
553 | * gpiolib gpio_direction_output callback function. The setting of the pin | ||
554 | * mux function as 'gpio output' will be handled by the pinctrl susbsystem | ||
555 | * interface. | ||
556 | */ | ||
557 | static int samsung_gpio_direction_output(struct gpio_chip *gc, unsigned offset, | ||
558 | int value) | ||
559 | { | ||
560 | samsung_gpio_set(gc, offset, value); | ||
561 | return pinctrl_gpio_direction_output(gc->base + offset); | ||
562 | } | ||
563 | |||
564 | /* | ||
565 | * gpiolib gpio_to_irq callback function. Creates a mapping between a GPIO pin | ||
566 | * and a virtual IRQ, if not already present. | ||
567 | */ | ||
568 | static int samsung_gpio_to_irq(struct gpio_chip *gc, unsigned offset) | ||
569 | { | ||
570 | struct samsung_pin_bank *bank = gc_to_pin_bank(gc); | ||
571 | unsigned int virq; | ||
572 | |||
573 | if (!bank->irq_domain) | ||
574 | return -ENXIO; | ||
575 | |||
576 | virq = irq_create_mapping(bank->irq_domain, offset); | ||
577 | |||
578 | return (virq) ? : -ENXIO; | ||
579 | } | ||
580 | |||
581 | /* | ||
582 | * Parse the pin names listed in the 'samsung,pins' property and convert it | ||
583 | * into a list of gpio numbers are create a pin group from it. | ||
584 | */ | ||
585 | static int samsung_pinctrl_parse_dt_pins(struct platform_device *pdev, | ||
586 | struct device_node *cfg_np, | ||
587 | struct pinctrl_desc *pctl, | ||
588 | unsigned int **pin_list, | ||
589 | unsigned int *npins) | ||
590 | { | ||
591 | struct device *dev = &pdev->dev; | ||
592 | struct property *prop; | ||
593 | struct pinctrl_pin_desc const *pdesc = pctl->pins; | ||
594 | unsigned int idx = 0, cnt; | ||
595 | const char *pin_name; | ||
596 | |||
597 | *npins = of_property_count_strings(cfg_np, "samsung,pins"); | ||
598 | if (IS_ERR_VALUE(*npins)) { | ||
599 | dev_err(dev, "invalid pin list in %s node", cfg_np->name); | ||
600 | return -EINVAL; | ||
601 | } | ||
602 | |||
603 | *pin_list = devm_kzalloc(dev, *npins * sizeof(**pin_list), GFP_KERNEL); | ||
604 | if (!*pin_list) { | ||
605 | dev_err(dev, "failed to allocate memory for pin list\n"); | ||
606 | return -ENOMEM; | ||
607 | } | ||
608 | |||
609 | of_property_for_each_string(cfg_np, "samsung,pins", prop, pin_name) { | ||
610 | for (cnt = 0; cnt < pctl->npins; cnt++) { | ||
611 | if (pdesc[cnt].name) { | ||
612 | if (!strcmp(pin_name, pdesc[cnt].name)) { | ||
613 | (*pin_list)[idx++] = pdesc[cnt].number; | ||
614 | break; | ||
615 | } | ||
616 | } | ||
617 | } | ||
618 | if (cnt == pctl->npins) { | ||
619 | dev_err(dev, "pin %s not valid in %s node\n", | ||
620 | pin_name, cfg_np->name); | ||
621 | devm_kfree(dev, *pin_list); | ||
622 | return -EINVAL; | ||
623 | } | ||
624 | } | ||
625 | |||
626 | return 0; | ||
627 | } | ||
628 | |||
629 | /* | ||
630 | * Parse the information about all the available pin groups and pin functions | ||
631 | * from device node of the pin-controller. A pin group is formed with all | ||
632 | * the pins listed in the "samsung,pins" property. | ||
633 | */ | ||
634 | static int samsung_pinctrl_parse_dt(struct platform_device *pdev, | ||
635 | struct samsung_pinctrl_drv_data *drvdata) | ||
636 | { | ||
637 | struct device *dev = &pdev->dev; | ||
638 | struct device_node *dev_np = dev->of_node; | ||
639 | struct device_node *cfg_np; | ||
640 | struct samsung_pin_group *groups, *grp; | ||
641 | struct samsung_pmx_func *functions, *func; | ||
642 | unsigned *pin_list; | ||
643 | unsigned int npins, grp_cnt, func_idx = 0; | ||
644 | char *gname, *fname; | ||
645 | int ret; | ||
646 | |||
647 | grp_cnt = of_get_child_count(dev_np); | ||
648 | if (!grp_cnt) | ||
649 | return -EINVAL; | ||
650 | |||
651 | groups = devm_kzalloc(dev, grp_cnt * sizeof(*groups), GFP_KERNEL); | ||
652 | if (!groups) { | ||
653 | dev_err(dev, "failed allocate memory for ping group list\n"); | ||
654 | return -EINVAL; | ||
655 | } | ||
656 | grp = groups; | ||
657 | |||
658 | functions = devm_kzalloc(dev, grp_cnt * sizeof(*functions), GFP_KERNEL); | ||
659 | if (!functions) { | ||
660 | dev_err(dev, "failed to allocate memory for function list\n"); | ||
661 | return -EINVAL; | ||
662 | } | ||
663 | func = functions; | ||
664 | |||
665 | /* | ||
666 | * Iterate over all the child nodes of the pin controller node | ||
667 | * and create pin groups and pin function lists. | ||
668 | */ | ||
669 | for_each_child_of_node(dev_np, cfg_np) { | ||
670 | u32 function; | ||
671 | if (!of_find_property(cfg_np, "samsung,pins", NULL)) | ||
672 | continue; | ||
673 | |||
674 | ret = samsung_pinctrl_parse_dt_pins(pdev, cfg_np, | ||
675 | &drvdata->pctl, &pin_list, &npins); | ||
676 | if (ret) | ||
677 | return ret; | ||
678 | |||
679 | /* derive pin group name from the node name */ | ||
680 | gname = devm_kzalloc(dev, strlen(cfg_np->name) + GSUFFIX_LEN, | ||
681 | GFP_KERNEL); | ||
682 | if (!gname) { | ||
683 | dev_err(dev, "failed to alloc memory for group name\n"); | ||
684 | return -ENOMEM; | ||
685 | } | ||
686 | sprintf(gname, "%s%s", cfg_np->name, GROUP_SUFFIX); | ||
687 | |||
688 | grp->name = gname; | ||
689 | grp->pins = pin_list; | ||
690 | grp->num_pins = npins; | ||
691 | of_property_read_u32(cfg_np, "samsung,pin-function", &function); | ||
692 | grp->func = function; | ||
693 | grp++; | ||
694 | |||
695 | if (!of_find_property(cfg_np, "samsung,pin-function", NULL)) | ||
696 | continue; | ||
697 | |||
698 | /* derive function name from the node name */ | ||
699 | fname = devm_kzalloc(dev, strlen(cfg_np->name) + FSUFFIX_LEN, | ||
700 | GFP_KERNEL); | ||
701 | if (!fname) { | ||
702 | dev_err(dev, "failed to alloc memory for func name\n"); | ||
703 | return -ENOMEM; | ||
704 | } | ||
705 | sprintf(fname, "%s%s", cfg_np->name, FUNCTION_SUFFIX); | ||
706 | |||
707 | func->name = fname; | ||
708 | func->groups = devm_kzalloc(dev, sizeof(char *), GFP_KERNEL); | ||
709 | if (!func->groups) { | ||
710 | dev_err(dev, "failed to alloc memory for group list " | ||
711 | "in pin function"); | ||
712 | return -ENOMEM; | ||
713 | } | ||
714 | func->groups[0] = gname; | ||
715 | func->num_groups = 1; | ||
716 | func++; | ||
717 | func_idx++; | ||
718 | } | ||
719 | |||
720 | drvdata->pin_groups = groups; | ||
721 | drvdata->nr_groups = grp_cnt; | ||
722 | drvdata->pmx_functions = functions; | ||
723 | drvdata->nr_functions = func_idx; | ||
724 | |||
725 | return 0; | ||
726 | } | ||
727 | |||
728 | /* register the pinctrl interface with the pinctrl subsystem */ | ||
729 | static int samsung_pinctrl_register(struct platform_device *pdev, | ||
730 | struct samsung_pinctrl_drv_data *drvdata) | ||
731 | { | ||
732 | struct pinctrl_desc *ctrldesc = &drvdata->pctl; | ||
733 | struct pinctrl_pin_desc *pindesc, *pdesc; | ||
734 | struct samsung_pin_bank *pin_bank; | ||
735 | char *pin_names; | ||
736 | int pin, bank, ret; | ||
737 | |||
738 | ctrldesc->name = "samsung-pinctrl"; | ||
739 | ctrldesc->owner = THIS_MODULE; | ||
740 | ctrldesc->pctlops = &samsung_pctrl_ops; | ||
741 | ctrldesc->pmxops = &samsung_pinmux_ops; | ||
742 | ctrldesc->confops = &samsung_pinconf_ops; | ||
743 | |||
744 | pindesc = devm_kzalloc(&pdev->dev, sizeof(*pindesc) * | ||
745 | drvdata->ctrl->nr_pins, GFP_KERNEL); | ||
746 | if (!pindesc) { | ||
747 | dev_err(&pdev->dev, "mem alloc for pin descriptors failed\n"); | ||
748 | return -ENOMEM; | ||
749 | } | ||
750 | ctrldesc->pins = pindesc; | ||
751 | ctrldesc->npins = drvdata->ctrl->nr_pins; | ||
752 | |||
753 | /* dynamically populate the pin number and pin name for pindesc */ | ||
754 | for (pin = 0, pdesc = pindesc; pin < ctrldesc->npins; pin++, pdesc++) | ||
755 | pdesc->number = pin + drvdata->ctrl->base; | ||
756 | |||
757 | /* | ||
758 | * allocate space for storing the dynamically generated names for all | ||
759 | * the pins which belong to this pin-controller. | ||
760 | */ | ||
761 | pin_names = devm_kzalloc(&pdev->dev, sizeof(char) * PIN_NAME_LENGTH * | ||
762 | drvdata->ctrl->nr_pins, GFP_KERNEL); | ||
763 | if (!pin_names) { | ||
764 | dev_err(&pdev->dev, "mem alloc for pin names failed\n"); | ||
765 | return -ENOMEM; | ||
766 | } | ||
767 | |||
768 | /* for each pin, the name of the pin is pin-bank name + pin number */ | ||
769 | for (bank = 0; bank < drvdata->ctrl->nr_banks; bank++) { | ||
770 | pin_bank = &drvdata->ctrl->pin_banks[bank]; | ||
771 | for (pin = 0; pin < pin_bank->nr_pins; pin++) { | ||
772 | sprintf(pin_names, "%s-%d", pin_bank->name, pin); | ||
773 | pdesc = pindesc + pin_bank->pin_base + pin; | ||
774 | pdesc->name = pin_names; | ||
775 | pin_names += PIN_NAME_LENGTH; | ||
776 | } | ||
777 | } | ||
778 | |||
779 | ret = samsung_pinctrl_parse_dt(pdev, drvdata); | ||
780 | if (ret) | ||
781 | return ret; | ||
782 | |||
783 | drvdata->pctl_dev = pinctrl_register(ctrldesc, &pdev->dev, drvdata); | ||
784 | if (!drvdata->pctl_dev) { | ||
785 | dev_err(&pdev->dev, "could not register pinctrl driver\n"); | ||
786 | return -EINVAL; | ||
787 | } | ||
788 | |||
789 | for (bank = 0; bank < drvdata->ctrl->nr_banks; ++bank) { | ||
790 | pin_bank = &drvdata->ctrl->pin_banks[bank]; | ||
791 | pin_bank->grange.name = pin_bank->name; | ||
792 | pin_bank->grange.id = bank; | ||
793 | pin_bank->grange.pin_base = pin_bank->pin_base; | ||
794 | pin_bank->grange.base = pin_bank->gpio_chip.base; | ||
795 | pin_bank->grange.npins = pin_bank->gpio_chip.ngpio; | ||
796 | pin_bank->grange.gc = &pin_bank->gpio_chip; | ||
797 | pinctrl_add_gpio_range(drvdata->pctl_dev, &pin_bank->grange); | ||
798 | } | ||
799 | |||
800 | return 0; | ||
801 | } | ||
802 | |||
803 | static const struct gpio_chip samsung_gpiolib_chip = { | ||
804 | .set = samsung_gpio_set, | ||
805 | .get = samsung_gpio_get, | ||
806 | .direction_input = samsung_gpio_direction_input, | ||
807 | .direction_output = samsung_gpio_direction_output, | ||
808 | .to_irq = samsung_gpio_to_irq, | ||
809 | .owner = THIS_MODULE, | ||
810 | }; | ||
811 | |||
812 | /* register the gpiolib interface with the gpiolib subsystem */ | ||
813 | static int samsung_gpiolib_register(struct platform_device *pdev, | ||
814 | struct samsung_pinctrl_drv_data *drvdata) | ||
815 | { | ||
816 | struct samsung_pin_ctrl *ctrl = drvdata->ctrl; | ||
817 | struct samsung_pin_bank *bank = ctrl->pin_banks; | ||
818 | struct gpio_chip *gc; | ||
819 | int ret; | ||
820 | int i; | ||
821 | |||
822 | for (i = 0; i < ctrl->nr_banks; ++i, ++bank) { | ||
823 | bank->gpio_chip = samsung_gpiolib_chip; | ||
824 | |||
825 | gc = &bank->gpio_chip; | ||
826 | gc->base = ctrl->base + bank->pin_base; | ||
827 | gc->ngpio = bank->nr_pins; | ||
828 | gc->dev = &pdev->dev; | ||
829 | gc->of_node = bank->of_node; | ||
830 | gc->label = bank->name; | ||
831 | |||
832 | ret = gpiochip_add(gc); | ||
833 | if (ret) { | ||
834 | dev_err(&pdev->dev, "failed to register gpio_chip %s, error code: %d\n", | ||
835 | gc->label, ret); | ||
836 | goto fail; | ||
837 | } | ||
838 | } | ||
839 | |||
840 | return 0; | ||
841 | |||
842 | fail: | ||
843 | for (--i, --bank; i >= 0; --i, --bank) | ||
844 | if (gpiochip_remove(&bank->gpio_chip)) | ||
845 | dev_err(&pdev->dev, "gpio chip %s remove failed\n", | ||
846 | bank->gpio_chip.label); | ||
847 | return ret; | ||
848 | } | ||
849 | |||
850 | /* unregister the gpiolib interface with the gpiolib subsystem */ | ||
851 | static int samsung_gpiolib_unregister(struct platform_device *pdev, | ||
852 | struct samsung_pinctrl_drv_data *drvdata) | ||
853 | { | ||
854 | struct samsung_pin_ctrl *ctrl = drvdata->ctrl; | ||
855 | struct samsung_pin_bank *bank = ctrl->pin_banks; | ||
856 | int ret = 0; | ||
857 | int i; | ||
858 | |||
859 | for (i = 0; !ret && i < ctrl->nr_banks; ++i, ++bank) | ||
860 | ret = gpiochip_remove(&bank->gpio_chip); | ||
861 | |||
862 | if (ret) | ||
863 | dev_err(&pdev->dev, "gpio chip remove failed\n"); | ||
864 | |||
865 | return ret; | ||
866 | } | ||
867 | |||
868 | static const struct of_device_id samsung_pinctrl_dt_match[]; | ||
869 | |||
870 | /* retrieve the soc specific data */ | ||
871 | static struct samsung_pin_ctrl *samsung_pinctrl_get_soc_data( | ||
872 | struct samsung_pinctrl_drv_data *d, | ||
873 | struct platform_device *pdev) | ||
874 | { | ||
875 | int id; | ||
876 | const struct of_device_id *match; | ||
877 | struct device_node *node = pdev->dev.of_node; | ||
878 | struct device_node *np; | ||
879 | struct samsung_pin_ctrl *ctrl; | ||
880 | struct samsung_pin_bank *bank; | ||
881 | int i; | ||
882 | |||
883 | id = of_alias_get_id(node, "pinctrl"); | ||
884 | if (id < 0) { | ||
885 | dev_err(&pdev->dev, "failed to get alias id\n"); | ||
886 | return NULL; | ||
887 | } | ||
888 | match = of_match_node(samsung_pinctrl_dt_match, node); | ||
889 | ctrl = (struct samsung_pin_ctrl *)match->data + id; | ||
890 | |||
891 | bank = ctrl->pin_banks; | ||
892 | for (i = 0; i < ctrl->nr_banks; ++i, ++bank) { | ||
893 | spin_lock_init(&bank->slock); | ||
894 | bank->drvdata = d; | ||
895 | bank->pin_base = ctrl->nr_pins; | ||
896 | ctrl->nr_pins += bank->nr_pins; | ||
897 | } | ||
898 | |||
899 | for_each_child_of_node(node, np) { | ||
900 | if (!of_find_property(np, "gpio-controller", NULL)) | ||
901 | continue; | ||
902 | bank = ctrl->pin_banks; | ||
903 | for (i = 0; i < ctrl->nr_banks; ++i, ++bank) { | ||
904 | if (!strcmp(bank->name, np->name)) { | ||
905 | bank->of_node = np; | ||
906 | break; | ||
907 | } | ||
908 | } | ||
909 | } | ||
910 | |||
911 | ctrl->base = pin_base; | ||
912 | pin_base += ctrl->nr_pins; | ||
913 | |||
914 | return ctrl; | ||
915 | } | ||
916 | |||
917 | static int samsung_pinctrl_probe(struct platform_device *pdev) | ||
918 | { | ||
919 | struct samsung_pinctrl_drv_data *drvdata; | ||
920 | struct device *dev = &pdev->dev; | ||
921 | struct samsung_pin_ctrl *ctrl; | ||
922 | struct resource *res; | ||
923 | int ret; | ||
924 | |||
925 | if (!dev->of_node) { | ||
926 | dev_err(dev, "device tree node not found\n"); | ||
927 | return -ENODEV; | ||
928 | } | ||
929 | |||
930 | drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL); | ||
931 | if (!drvdata) { | ||
932 | dev_err(dev, "failed to allocate memory for driver's " | ||
933 | "private data\n"); | ||
934 | return -ENOMEM; | ||
935 | } | ||
936 | |||
937 | ctrl = samsung_pinctrl_get_soc_data(drvdata, pdev); | ||
938 | if (!ctrl) { | ||
939 | dev_err(&pdev->dev, "driver data not available\n"); | ||
940 | return -EINVAL; | ||
941 | } | ||
942 | drvdata->ctrl = ctrl; | ||
943 | drvdata->dev = dev; | ||
944 | |||
945 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
946 | drvdata->virt_base = devm_ioremap_resource(&pdev->dev, res); | ||
947 | if (IS_ERR(drvdata->virt_base)) | ||
948 | return PTR_ERR(drvdata->virt_base); | ||
949 | |||
950 | res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); | ||
951 | if (res) | ||
952 | drvdata->irq = res->start; | ||
953 | |||
954 | ret = samsung_gpiolib_register(pdev, drvdata); | ||
955 | if (ret) | ||
956 | return ret; | ||
957 | |||
958 | ret = samsung_pinctrl_register(pdev, drvdata); | ||
959 | if (ret) { | ||
960 | samsung_gpiolib_unregister(pdev, drvdata); | ||
961 | return ret; | ||
962 | } | ||
963 | |||
964 | if (ctrl->eint_gpio_init) | ||
965 | ctrl->eint_gpio_init(drvdata); | ||
966 | if (ctrl->eint_wkup_init) | ||
967 | ctrl->eint_wkup_init(drvdata); | ||
968 | |||
969 | platform_set_drvdata(pdev, drvdata); | ||
970 | |||
971 | /* Add to the global list */ | ||
972 | list_add_tail(&drvdata->node, &drvdata_list); | ||
973 | |||
974 | return 0; | ||
975 | } | ||
976 | |||
977 | #ifdef CONFIG_PM | ||
978 | |||
979 | /** | ||
980 | * samsung_pinctrl_suspend_dev - save pinctrl state for suspend for a device | ||
981 | * | ||
982 | * Save data for all banks handled by this device. | ||
983 | */ | ||
984 | static void samsung_pinctrl_suspend_dev( | ||
985 | struct samsung_pinctrl_drv_data *drvdata) | ||
986 | { | ||
987 | struct samsung_pin_ctrl *ctrl = drvdata->ctrl; | ||
988 | void __iomem *virt_base = drvdata->virt_base; | ||
989 | int i; | ||
990 | |||
991 | for (i = 0; i < ctrl->nr_banks; i++) { | ||
992 | struct samsung_pin_bank *bank = &ctrl->pin_banks[i]; | ||
993 | void __iomem *reg = virt_base + bank->pctl_offset; | ||
994 | |||
995 | u8 *offs = bank->type->reg_offset; | ||
996 | u8 *widths = bank->type->fld_width; | ||
997 | enum pincfg_type type; | ||
998 | |||
999 | /* Registers without a powerdown config aren't lost */ | ||
1000 | if (!widths[PINCFG_TYPE_CON_PDN]) | ||
1001 | continue; | ||
1002 | |||
1003 | for (type = 0; type < PINCFG_TYPE_NUM; type++) | ||
1004 | if (widths[type]) | ||
1005 | bank->pm_save[type] = readl(reg + offs[type]); | ||
1006 | |||
1007 | if (widths[PINCFG_TYPE_FUNC] * bank->nr_pins > 32) { | ||
1008 | /* Some banks have two config registers */ | ||
1009 | bank->pm_save[PINCFG_TYPE_NUM] = | ||
1010 | readl(reg + offs[PINCFG_TYPE_FUNC] + 4); | ||
1011 | pr_debug("Save %s @ %p (con %#010x %08x)\n", | ||
1012 | bank->name, reg, | ||
1013 | bank->pm_save[PINCFG_TYPE_FUNC], | ||
1014 | bank->pm_save[PINCFG_TYPE_NUM]); | ||
1015 | } else { | ||
1016 | pr_debug("Save %s @ %p (con %#010x)\n", bank->name, | ||
1017 | reg, bank->pm_save[PINCFG_TYPE_FUNC]); | ||
1018 | } | ||
1019 | } | ||
1020 | |||
1021 | if (ctrl->suspend) | ||
1022 | ctrl->suspend(drvdata); | ||
1023 | } | ||
1024 | |||
1025 | /** | ||
1026 | * samsung_pinctrl_resume_dev - restore pinctrl state from suspend for a device | ||
1027 | * | ||
1028 | * Restore one of the banks that was saved during suspend. | ||
1029 | * | ||
1030 | * We don't bother doing anything complicated to avoid glitching lines since | ||
1031 | * we're called before pad retention is turned off. | ||
1032 | */ | ||
1033 | static void samsung_pinctrl_resume_dev(struct samsung_pinctrl_drv_data *drvdata) | ||
1034 | { | ||
1035 | struct samsung_pin_ctrl *ctrl = drvdata->ctrl; | ||
1036 | void __iomem *virt_base = drvdata->virt_base; | ||
1037 | int i; | ||
1038 | |||
1039 | if (ctrl->resume) | ||
1040 | ctrl->resume(drvdata); | ||
1041 | |||
1042 | for (i = 0; i < ctrl->nr_banks; i++) { | ||
1043 | struct samsung_pin_bank *bank = &ctrl->pin_banks[i]; | ||
1044 | void __iomem *reg = virt_base + bank->pctl_offset; | ||
1045 | |||
1046 | u8 *offs = bank->type->reg_offset; | ||
1047 | u8 *widths = bank->type->fld_width; | ||
1048 | enum pincfg_type type; | ||
1049 | |||
1050 | /* Registers without a powerdown config aren't lost */ | ||
1051 | if (!widths[PINCFG_TYPE_CON_PDN]) | ||
1052 | continue; | ||
1053 | |||
1054 | if (widths[PINCFG_TYPE_FUNC] * bank->nr_pins > 32) { | ||
1055 | /* Some banks have two config registers */ | ||
1056 | pr_debug("%s @ %p (con %#010x %08x => %#010x %08x)\n", | ||
1057 | bank->name, reg, | ||
1058 | readl(reg + offs[PINCFG_TYPE_FUNC]), | ||
1059 | readl(reg + offs[PINCFG_TYPE_FUNC] + 4), | ||
1060 | bank->pm_save[PINCFG_TYPE_FUNC], | ||
1061 | bank->pm_save[PINCFG_TYPE_NUM]); | ||
1062 | writel(bank->pm_save[PINCFG_TYPE_NUM], | ||
1063 | reg + offs[PINCFG_TYPE_FUNC] + 4); | ||
1064 | } else { | ||
1065 | pr_debug("%s @ %p (con %#010x => %#010x)\n", bank->name, | ||
1066 | reg, readl(reg + offs[PINCFG_TYPE_FUNC]), | ||
1067 | bank->pm_save[PINCFG_TYPE_FUNC]); | ||
1068 | } | ||
1069 | for (type = 0; type < PINCFG_TYPE_NUM; type++) | ||
1070 | if (widths[type]) | ||
1071 | writel(bank->pm_save[type], reg + offs[type]); | ||
1072 | } | ||
1073 | } | ||
1074 | |||
1075 | /** | ||
1076 | * samsung_pinctrl_suspend - save pinctrl state for suspend | ||
1077 | * | ||
1078 | * Save data for all banks across all devices. | ||
1079 | */ | ||
1080 | static int samsung_pinctrl_suspend(void) | ||
1081 | { | ||
1082 | struct samsung_pinctrl_drv_data *drvdata; | ||
1083 | |||
1084 | list_for_each_entry(drvdata, &drvdata_list, node) { | ||
1085 | samsung_pinctrl_suspend_dev(drvdata); | ||
1086 | } | ||
1087 | |||
1088 | return 0; | ||
1089 | } | ||
1090 | |||
1091 | /** | ||
1092 | * samsung_pinctrl_resume - restore pinctrl state for suspend | ||
1093 | * | ||
1094 | * Restore data for all banks across all devices. | ||
1095 | */ | ||
1096 | static void samsung_pinctrl_resume(void) | ||
1097 | { | ||
1098 | struct samsung_pinctrl_drv_data *drvdata; | ||
1099 | |||
1100 | list_for_each_entry_reverse(drvdata, &drvdata_list, node) { | ||
1101 | samsung_pinctrl_resume_dev(drvdata); | ||
1102 | } | ||
1103 | } | ||
1104 | |||
1105 | #else | ||
1106 | #define samsung_pinctrl_suspend NULL | ||
1107 | #define samsung_pinctrl_resume NULL | ||
1108 | #endif | ||
1109 | |||
1110 | static struct syscore_ops samsung_pinctrl_syscore_ops = { | ||
1111 | .suspend = samsung_pinctrl_suspend, | ||
1112 | .resume = samsung_pinctrl_resume, | ||
1113 | }; | ||
1114 | |||
1115 | static const struct of_device_id samsung_pinctrl_dt_match[] = { | ||
1116 | #ifdef CONFIG_PINCTRL_EXYNOS | ||
1117 | { .compatible = "samsung,exynos3250-pinctrl", | ||
1118 | .data = (void *)exynos3250_pin_ctrl }, | ||
1119 | { .compatible = "samsung,exynos4210-pinctrl", | ||
1120 | .data = (void *)exynos4210_pin_ctrl }, | ||
1121 | { .compatible = "samsung,exynos4x12-pinctrl", | ||
1122 | .data = (void *)exynos4x12_pin_ctrl }, | ||
1123 | { .compatible = "samsung,exynos5250-pinctrl", | ||
1124 | .data = (void *)exynos5250_pin_ctrl }, | ||
1125 | { .compatible = "samsung,exynos5260-pinctrl", | ||
1126 | .data = (void *)exynos5260_pin_ctrl }, | ||
1127 | { .compatible = "samsung,exynos5420-pinctrl", | ||
1128 | .data = (void *)exynos5420_pin_ctrl }, | ||
1129 | { .compatible = "samsung,s5pv210-pinctrl", | ||
1130 | .data = (void *)s5pv210_pin_ctrl }, | ||
1131 | #endif | ||
1132 | #ifdef CONFIG_PINCTRL_S3C64XX | ||
1133 | { .compatible = "samsung,s3c64xx-pinctrl", | ||
1134 | .data = s3c64xx_pin_ctrl }, | ||
1135 | #endif | ||
1136 | #ifdef CONFIG_PINCTRL_S3C24XX | ||
1137 | { .compatible = "samsung,s3c2412-pinctrl", | ||
1138 | .data = s3c2412_pin_ctrl }, | ||
1139 | { .compatible = "samsung,s3c2416-pinctrl", | ||
1140 | .data = s3c2416_pin_ctrl }, | ||
1141 | { .compatible = "samsung,s3c2440-pinctrl", | ||
1142 | .data = s3c2440_pin_ctrl }, | ||
1143 | { .compatible = "samsung,s3c2450-pinctrl", | ||
1144 | .data = s3c2450_pin_ctrl }, | ||
1145 | #endif | ||
1146 | {}, | ||
1147 | }; | ||
1148 | MODULE_DEVICE_TABLE(of, samsung_pinctrl_dt_match); | ||
1149 | |||
1150 | static struct platform_driver samsung_pinctrl_driver = { | ||
1151 | .probe = samsung_pinctrl_probe, | ||
1152 | .driver = { | ||
1153 | .name = "samsung-pinctrl", | ||
1154 | .owner = THIS_MODULE, | ||
1155 | .of_match_table = samsung_pinctrl_dt_match, | ||
1156 | }, | ||
1157 | }; | ||
1158 | |||
1159 | static int __init samsung_pinctrl_drv_register(void) | ||
1160 | { | ||
1161 | /* | ||
1162 | * Register syscore ops for save/restore of registers across suspend. | ||
1163 | * It's important to ensure that this driver is running at an earlier | ||
1164 | * initcall level than any arch-specific init calls that install syscore | ||
1165 | * ops that turn off pad retention (like exynos_pm_resume). | ||
1166 | */ | ||
1167 | register_syscore_ops(&samsung_pinctrl_syscore_ops); | ||
1168 | |||
1169 | return platform_driver_register(&samsung_pinctrl_driver); | ||
1170 | } | ||
1171 | postcore_initcall(samsung_pinctrl_drv_register); | ||
1172 | |||
1173 | static void __exit samsung_pinctrl_drv_unregister(void) | ||
1174 | { | ||
1175 | platform_driver_unregister(&samsung_pinctrl_driver); | ||
1176 | } | ||
1177 | module_exit(samsung_pinctrl_drv_unregister); | ||
1178 | |||
1179 | MODULE_AUTHOR("Thomas Abraham <thomas.ab@samsung.com>"); | ||
1180 | MODULE_DESCRIPTION("Samsung pinctrl driver"); | ||
1181 | MODULE_LICENSE("GPL v2"); | ||