diff options
Diffstat (limited to 'drivers/pinctrl/pinctrl-imx.c')
-rw-r--r-- | drivers/pinctrl/pinctrl-imx.c | 627 |
1 files changed, 627 insertions, 0 deletions
diff --git a/drivers/pinctrl/pinctrl-imx.c b/drivers/pinctrl/pinctrl-imx.c new file mode 100644 index 00000000000..8faf613ff1b --- /dev/null +++ b/drivers/pinctrl/pinctrl-imx.c | |||
@@ -0,0 +1,627 @@ | |||
1 | /* | ||
2 | * Core driver for the imx pin controller | ||
3 | * | ||
4 | * Copyright (C) 2012 Freescale Semiconductor, Inc. | ||
5 | * Copyright (C) 2012 Linaro Ltd. | ||
6 | * | ||
7 | * Author: Dong Aisheng <dong.aisheng@linaro.org> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; either version 2 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | */ | ||
14 | |||
15 | #include <linux/err.h> | ||
16 | #include <linux/init.h> | ||
17 | #include <linux/io.h> | ||
18 | #include <linux/module.h> | ||
19 | #include <linux/of.h> | ||
20 | #include <linux/of_device.h> | ||
21 | #include <linux/pinctrl/machine.h> | ||
22 | #include <linux/pinctrl/pinconf.h> | ||
23 | #include <linux/pinctrl/pinctrl.h> | ||
24 | #include <linux/pinctrl/pinmux.h> | ||
25 | #include <linux/slab.h> | ||
26 | |||
27 | #include "core.h" | ||
28 | #include "pinctrl-imx.h" | ||
29 | |||
30 | #define IMX_PMX_DUMP(info, p, m, c, n) \ | ||
31 | { \ | ||
32 | int i, j; \ | ||
33 | printk("Format: Pin Mux Config\n"); \ | ||
34 | for (i = 0; i < n; i++) { \ | ||
35 | j = p[i]; \ | ||
36 | printk("%s %d 0x%lx\n", \ | ||
37 | info->pins[j].name, \ | ||
38 | m[i], c[i]); \ | ||
39 | } \ | ||
40 | } | ||
41 | |||
42 | /* The bits in CONFIG cell defined in binding doc*/ | ||
43 | #define IMX_NO_PAD_CTL 0x80000000 /* no pin config need */ | ||
44 | #define IMX_PAD_SION 0x40000000 /* set SION */ | ||
45 | |||
46 | /** | ||
47 | * @dev: a pointer back to containing device | ||
48 | * @base: the offset to the controller in virtual memory | ||
49 | */ | ||
50 | struct imx_pinctrl { | ||
51 | struct device *dev; | ||
52 | struct pinctrl_dev *pctl; | ||
53 | void __iomem *base; | ||
54 | const struct imx_pinctrl_soc_info *info; | ||
55 | }; | ||
56 | |||
57 | static const struct imx_pin_reg *imx_find_pin_reg( | ||
58 | const struct imx_pinctrl_soc_info *info, | ||
59 | unsigned pin, bool is_mux, unsigned mux) | ||
60 | { | ||
61 | const struct imx_pin_reg *pin_reg = NULL; | ||
62 | int i; | ||
63 | |||
64 | for (i = 0; i < info->npin_regs; i++) { | ||
65 | pin_reg = &info->pin_regs[i]; | ||
66 | if (pin_reg->pid != pin) | ||
67 | continue; | ||
68 | if (!is_mux) | ||
69 | break; | ||
70 | else if (pin_reg->mux_mode == (mux & IMX_MUX_MASK)) | ||
71 | break; | ||
72 | } | ||
73 | |||
74 | if (!pin_reg) { | ||
75 | dev_err(info->dev, "Pin(%s): unable to find pin reg map\n", | ||
76 | info->pins[pin].name); | ||
77 | return NULL; | ||
78 | } | ||
79 | |||
80 | return pin_reg; | ||
81 | } | ||
82 | |||
83 | static const inline struct imx_pin_group *imx_pinctrl_find_group_by_name( | ||
84 | const struct imx_pinctrl_soc_info *info, | ||
85 | const char *name) | ||
86 | { | ||
87 | const struct imx_pin_group *grp = NULL; | ||
88 | int i; | ||
89 | |||
90 | for (i = 0; i < info->ngroups; i++) { | ||
91 | if (!strcmp(info->groups[i].name, name)) { | ||
92 | grp = &info->groups[i]; | ||
93 | break; | ||
94 | } | ||
95 | } | ||
96 | |||
97 | return grp; | ||
98 | } | ||
99 | |||
100 | static int imx_get_groups_count(struct pinctrl_dev *pctldev) | ||
101 | { | ||
102 | struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); | ||
103 | const struct imx_pinctrl_soc_info *info = ipctl->info; | ||
104 | |||
105 | return info->ngroups; | ||
106 | } | ||
107 | |||
108 | static const char *imx_get_group_name(struct pinctrl_dev *pctldev, | ||
109 | unsigned selector) | ||
110 | { | ||
111 | struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); | ||
112 | const struct imx_pinctrl_soc_info *info = ipctl->info; | ||
113 | |||
114 | return info->groups[selector].name; | ||
115 | } | ||
116 | |||
117 | static int imx_get_group_pins(struct pinctrl_dev *pctldev, unsigned selector, | ||
118 | const unsigned **pins, | ||
119 | unsigned *npins) | ||
120 | { | ||
121 | struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); | ||
122 | const struct imx_pinctrl_soc_info *info = ipctl->info; | ||
123 | |||
124 | if (selector >= info->ngroups) | ||
125 | return -EINVAL; | ||
126 | |||
127 | *pins = info->groups[selector].pins; | ||
128 | *npins = info->groups[selector].npins; | ||
129 | |||
130 | return 0; | ||
131 | } | ||
132 | |||
133 | static void imx_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s, | ||
134 | unsigned offset) | ||
135 | { | ||
136 | seq_printf(s, "%s", dev_name(pctldev->dev)); | ||
137 | } | ||
138 | |||
139 | static int imx_dt_node_to_map(struct pinctrl_dev *pctldev, | ||
140 | struct device_node *np, | ||
141 | struct pinctrl_map **map, unsigned *num_maps) | ||
142 | { | ||
143 | struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); | ||
144 | const struct imx_pinctrl_soc_info *info = ipctl->info; | ||
145 | const struct imx_pin_group *grp; | ||
146 | struct pinctrl_map *new_map; | ||
147 | struct device_node *parent; | ||
148 | int map_num = 1; | ||
149 | int i; | ||
150 | |||
151 | /* | ||
152 | * first find the group of this node and check if we need create | ||
153 | * config maps for pins | ||
154 | */ | ||
155 | grp = imx_pinctrl_find_group_by_name(info, np->name); | ||
156 | if (!grp) { | ||
157 | dev_err(info->dev, "unable to find group for node %s\n", | ||
158 | np->name); | ||
159 | return -EINVAL; | ||
160 | } | ||
161 | |||
162 | for (i = 0; i < grp->npins; i++) { | ||
163 | if (!(grp->configs[i] & IMX_NO_PAD_CTL)) | ||
164 | map_num++; | ||
165 | } | ||
166 | |||
167 | new_map = kmalloc(sizeof(struct pinctrl_map) * map_num, GFP_KERNEL); | ||
168 | if (!new_map) | ||
169 | return -ENOMEM; | ||
170 | |||
171 | *map = new_map; | ||
172 | *num_maps = map_num; | ||
173 | |||
174 | /* create mux map */ | ||
175 | parent = of_get_parent(np); | ||
176 | if (!parent) | ||
177 | return -EINVAL; | ||
178 | new_map[0].type = PIN_MAP_TYPE_MUX_GROUP; | ||
179 | new_map[0].data.mux.function = parent->name; | ||
180 | new_map[0].data.mux.group = np->name; | ||
181 | of_node_put(parent); | ||
182 | |||
183 | /* create config map */ | ||
184 | new_map++; | ||
185 | for (i = 0; i < grp->npins; i++) { | ||
186 | if (!(grp->configs[i] & IMX_NO_PAD_CTL)) { | ||
187 | new_map[i].type = PIN_MAP_TYPE_CONFIGS_PIN; | ||
188 | new_map[i].data.configs.group_or_pin = | ||
189 | pin_get_name(pctldev, grp->pins[i]); | ||
190 | new_map[i].data.configs.configs = &grp->configs[i]; | ||
191 | new_map[i].data.configs.num_configs = 1; | ||
192 | } | ||
193 | } | ||
194 | |||
195 | dev_dbg(pctldev->dev, "maps: function %s group %s num %d\n", | ||
196 | new_map->data.mux.function, new_map->data.mux.group, map_num); | ||
197 | |||
198 | return 0; | ||
199 | } | ||
200 | |||
201 | static void imx_dt_free_map(struct pinctrl_dev *pctldev, | ||
202 | struct pinctrl_map *map, unsigned num_maps) | ||
203 | { | ||
204 | int i; | ||
205 | |||
206 | for (i = 0; i < num_maps; i++) | ||
207 | kfree(map); | ||
208 | } | ||
209 | |||
210 | static struct pinctrl_ops imx_pctrl_ops = { | ||
211 | .get_groups_count = imx_get_groups_count, | ||
212 | .get_group_name = imx_get_group_name, | ||
213 | .get_group_pins = imx_get_group_pins, | ||
214 | .pin_dbg_show = imx_pin_dbg_show, | ||
215 | .dt_node_to_map = imx_dt_node_to_map, | ||
216 | .dt_free_map = imx_dt_free_map, | ||
217 | |||
218 | }; | ||
219 | |||
220 | static int imx_pmx_enable(struct pinctrl_dev *pctldev, unsigned selector, | ||
221 | unsigned group) | ||
222 | { | ||
223 | struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); | ||
224 | const struct imx_pinctrl_soc_info *info = ipctl->info; | ||
225 | const struct imx_pin_reg *pin_reg; | ||
226 | const unsigned *pins, *mux; | ||
227 | unsigned int npins, pin_id; | ||
228 | int i; | ||
229 | |||
230 | /* | ||
231 | * Configure the mux mode for each pin in the group for a specific | ||
232 | * function. | ||
233 | */ | ||
234 | pins = info->groups[group].pins; | ||
235 | npins = info->groups[group].npins; | ||
236 | mux = info->groups[group].mux_mode; | ||
237 | |||
238 | WARN_ON(!pins || !npins || !mux); | ||
239 | |||
240 | dev_dbg(ipctl->dev, "enable function %s group %s\n", | ||
241 | info->functions[selector].name, info->groups[group].name); | ||
242 | |||
243 | for (i = 0; i < npins; i++) { | ||
244 | pin_id = pins[i]; | ||
245 | |||
246 | pin_reg = imx_find_pin_reg(info, pin_id, 1, mux[i]); | ||
247 | if (!pin_reg) | ||
248 | return -EINVAL; | ||
249 | |||
250 | if (!pin_reg->mux_reg) { | ||
251 | dev_err(ipctl->dev, "Pin(%s) does not support mux function\n", | ||
252 | info->pins[pin_id].name); | ||
253 | return -EINVAL; | ||
254 | } | ||
255 | |||
256 | writel(mux[i], ipctl->base + pin_reg->mux_reg); | ||
257 | dev_dbg(ipctl->dev, "write: offset 0x%x val 0x%x\n", | ||
258 | pin_reg->mux_reg, mux[i]); | ||
259 | |||
260 | /* some pins also need select input setting, set it if found */ | ||
261 | if (pin_reg->input_reg) { | ||
262 | writel(pin_reg->input_val, ipctl->base + pin_reg->input_reg); | ||
263 | dev_dbg(ipctl->dev, | ||
264 | "==>select_input: offset 0x%x val 0x%x\n", | ||
265 | pin_reg->input_reg, pin_reg->input_val); | ||
266 | } | ||
267 | } | ||
268 | |||
269 | return 0; | ||
270 | } | ||
271 | |||
272 | static void imx_pmx_disable(struct pinctrl_dev *pctldev, unsigned func_selector, | ||
273 | unsigned group_selector) | ||
274 | { | ||
275 | /* nothing to do here */ | ||
276 | } | ||
277 | |||
278 | static int imx_pmx_get_funcs_count(struct pinctrl_dev *pctldev) | ||
279 | { | ||
280 | struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); | ||
281 | const struct imx_pinctrl_soc_info *info = ipctl->info; | ||
282 | |||
283 | return info->nfunctions; | ||
284 | } | ||
285 | |||
286 | static const char *imx_pmx_get_func_name(struct pinctrl_dev *pctldev, | ||
287 | unsigned selector) | ||
288 | { | ||
289 | struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); | ||
290 | const struct imx_pinctrl_soc_info *info = ipctl->info; | ||
291 | |||
292 | return info->functions[selector].name; | ||
293 | } | ||
294 | |||
295 | static int imx_pmx_get_groups(struct pinctrl_dev *pctldev, unsigned selector, | ||
296 | const char * const **groups, | ||
297 | unsigned * const num_groups) | ||
298 | { | ||
299 | struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); | ||
300 | const struct imx_pinctrl_soc_info *info = ipctl->info; | ||
301 | |||
302 | *groups = info->functions[selector].groups; | ||
303 | *num_groups = info->functions[selector].num_groups; | ||
304 | |||
305 | return 0; | ||
306 | } | ||
307 | |||
308 | static struct pinmux_ops imx_pmx_ops = { | ||
309 | .get_functions_count = imx_pmx_get_funcs_count, | ||
310 | .get_function_name = imx_pmx_get_func_name, | ||
311 | .get_function_groups = imx_pmx_get_groups, | ||
312 | .enable = imx_pmx_enable, | ||
313 | .disable = imx_pmx_disable, | ||
314 | }; | ||
315 | |||
316 | static int imx_pinconf_get(struct pinctrl_dev *pctldev, | ||
317 | unsigned pin_id, unsigned long *config) | ||
318 | { | ||
319 | struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); | ||
320 | const struct imx_pinctrl_soc_info *info = ipctl->info; | ||
321 | const struct imx_pin_reg *pin_reg; | ||
322 | |||
323 | pin_reg = imx_find_pin_reg(info, pin_id, 0, 0); | ||
324 | if (!pin_reg) | ||
325 | return -EINVAL; | ||
326 | |||
327 | if (!pin_reg->conf_reg) { | ||
328 | dev_err(info->dev, "Pin(%s) does not support config function\n", | ||
329 | info->pins[pin_id].name); | ||
330 | return -EINVAL; | ||
331 | } | ||
332 | |||
333 | *config = readl(ipctl->base + pin_reg->conf_reg); | ||
334 | |||
335 | return 0; | ||
336 | } | ||
337 | |||
338 | static int imx_pinconf_set(struct pinctrl_dev *pctldev, | ||
339 | unsigned pin_id, unsigned long config) | ||
340 | { | ||
341 | struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); | ||
342 | const struct imx_pinctrl_soc_info *info = ipctl->info; | ||
343 | const struct imx_pin_reg *pin_reg; | ||
344 | |||
345 | pin_reg = imx_find_pin_reg(info, pin_id, 0, 0); | ||
346 | if (!pin_reg) | ||
347 | return -EINVAL; | ||
348 | |||
349 | if (!pin_reg->conf_reg) { | ||
350 | dev_err(info->dev, "Pin(%s) does not support config function\n", | ||
351 | info->pins[pin_id].name); | ||
352 | return -EINVAL; | ||
353 | } | ||
354 | |||
355 | dev_dbg(ipctl->dev, "pinconf set pin %s\n", | ||
356 | info->pins[pin_id].name); | ||
357 | |||
358 | writel(config, ipctl->base + pin_reg->conf_reg); | ||
359 | dev_dbg(ipctl->dev, "write: offset 0x%x val 0x%lx\n", | ||
360 | pin_reg->conf_reg, config); | ||
361 | |||
362 | return 0; | ||
363 | } | ||
364 | |||
365 | static void imx_pinconf_dbg_show(struct pinctrl_dev *pctldev, | ||
366 | struct seq_file *s, unsigned pin_id) | ||
367 | { | ||
368 | struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); | ||
369 | const struct imx_pinctrl_soc_info *info = ipctl->info; | ||
370 | const struct imx_pin_reg *pin_reg; | ||
371 | unsigned long config; | ||
372 | |||
373 | pin_reg = imx_find_pin_reg(info, pin_id, 0, 0); | ||
374 | if (!pin_reg || !pin_reg->conf_reg) { | ||
375 | seq_printf(s, "N/A"); | ||
376 | return; | ||
377 | } | ||
378 | |||
379 | config = readl(ipctl->base + pin_reg->conf_reg); | ||
380 | seq_printf(s, "0x%lx", config); | ||
381 | } | ||
382 | |||
383 | static void imx_pinconf_group_dbg_show(struct pinctrl_dev *pctldev, | ||
384 | struct seq_file *s, unsigned group) | ||
385 | { | ||
386 | struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); | ||
387 | const struct imx_pinctrl_soc_info *info = ipctl->info; | ||
388 | struct imx_pin_group *grp; | ||
389 | unsigned long config; | ||
390 | const char *name; | ||
391 | int i, ret; | ||
392 | |||
393 | if (group > info->ngroups) | ||
394 | return; | ||
395 | |||
396 | seq_printf(s, "\n"); | ||
397 | grp = &info->groups[group]; | ||
398 | for (i = 0; i < grp->npins; i++) { | ||
399 | name = pin_get_name(pctldev, grp->pins[i]); | ||
400 | ret = imx_pinconf_get(pctldev, grp->pins[i], &config); | ||
401 | if (ret) | ||
402 | return; | ||
403 | seq_printf(s, "%s: 0x%lx", name, config); | ||
404 | } | ||
405 | } | ||
406 | |||
407 | struct pinconf_ops imx_pinconf_ops = { | ||
408 | .pin_config_get = imx_pinconf_get, | ||
409 | .pin_config_set = imx_pinconf_set, | ||
410 | .pin_config_dbg_show = imx_pinconf_dbg_show, | ||
411 | .pin_config_group_dbg_show = imx_pinconf_group_dbg_show, | ||
412 | }; | ||
413 | |||
414 | static struct pinctrl_desc imx_pinctrl_desc = { | ||
415 | .pctlops = &imx_pctrl_ops, | ||
416 | .pmxops = &imx_pmx_ops, | ||
417 | .confops = &imx_pinconf_ops, | ||
418 | .owner = THIS_MODULE, | ||
419 | }; | ||
420 | |||
421 | /* decode pin id and mux from pin function id got from device tree*/ | ||
422 | static int imx_pinctrl_get_pin_id_and_mux(const struct imx_pinctrl_soc_info *info, | ||
423 | unsigned int pin_func_id, unsigned int *pin_id, | ||
424 | unsigned int *mux) | ||
425 | { | ||
426 | if (pin_func_id > info->npin_regs) | ||
427 | return -EINVAL; | ||
428 | |||
429 | *pin_id = info->pin_regs[pin_func_id].pid; | ||
430 | *mux = info->pin_regs[pin_func_id].mux_mode; | ||
431 | |||
432 | return 0; | ||
433 | } | ||
434 | |||
435 | static int __devinit imx_pinctrl_parse_groups(struct device_node *np, | ||
436 | struct imx_pin_group *grp, | ||
437 | struct imx_pinctrl_soc_info *info, | ||
438 | u32 index) | ||
439 | { | ||
440 | unsigned int pin_func_id; | ||
441 | int ret, size; | ||
442 | const const __be32 *list; | ||
443 | int i, j; | ||
444 | u32 config; | ||
445 | |||
446 | dev_dbg(info->dev, "group(%d): %s\n", index, np->name); | ||
447 | |||
448 | /* Initialise group */ | ||
449 | grp->name = np->name; | ||
450 | |||
451 | /* | ||
452 | * the binding format is fsl,pins = <PIN_FUNC_ID CONFIG ...>, | ||
453 | * do sanity check and calculate pins number | ||
454 | */ | ||
455 | list = of_get_property(np, "fsl,pins", &size); | ||
456 | /* we do not check return since it's safe node passed down */ | ||
457 | size /= sizeof(*list); | ||
458 | if (!size || size % 2) { | ||
459 | dev_err(info->dev, "wrong pins number or pins and configs should be pairs\n"); | ||
460 | return -EINVAL; | ||
461 | } | ||
462 | |||
463 | grp->npins = size / 2; | ||
464 | grp->pins = devm_kzalloc(info->dev, grp->npins * sizeof(unsigned int), | ||
465 | GFP_KERNEL); | ||
466 | grp->mux_mode = devm_kzalloc(info->dev, grp->npins * sizeof(unsigned int), | ||
467 | GFP_KERNEL); | ||
468 | grp->configs = devm_kzalloc(info->dev, grp->npins * sizeof(unsigned long), | ||
469 | GFP_KERNEL); | ||
470 | for (i = 0, j = 0; i < size; i += 2, j++) { | ||
471 | pin_func_id = be32_to_cpu(*list++); | ||
472 | ret = imx_pinctrl_get_pin_id_and_mux(info, pin_func_id, | ||
473 | &grp->pins[j], &grp->mux_mode[j]); | ||
474 | if (ret) { | ||
475 | dev_err(info->dev, "get invalid pin function id\n"); | ||
476 | return -EINVAL; | ||
477 | } | ||
478 | /* SION bit is in mux register */ | ||
479 | config = be32_to_cpu(*list++); | ||
480 | if (config & IMX_PAD_SION) | ||
481 | grp->mux_mode[j] |= IOMUXC_CONFIG_SION; | ||
482 | grp->configs[j] = config & ~IMX_PAD_SION; | ||
483 | } | ||
484 | |||
485 | #ifdef DEBUG | ||
486 | IMX_PMX_DUMP(info, grp->pins, grp->mux_mode, grp->configs, grp->npins); | ||
487 | #endif | ||
488 | return 0; | ||
489 | } | ||
490 | |||
491 | static int __devinit imx_pinctrl_parse_functions(struct device_node *np, | ||
492 | struct imx_pinctrl_soc_info *info, u32 index) | ||
493 | { | ||
494 | struct device_node *child; | ||
495 | struct imx_pmx_func *func; | ||
496 | struct imx_pin_group *grp; | ||
497 | int ret; | ||
498 | static u32 grp_index; | ||
499 | u32 i = 0; | ||
500 | |||
501 | dev_dbg(info->dev, "parse function(%d): %s\n", index, np->name); | ||
502 | |||
503 | func = &info->functions[index]; | ||
504 | |||
505 | /* Initialise function */ | ||
506 | func->name = np->name; | ||
507 | func->num_groups = of_get_child_count(np); | ||
508 | if (func->num_groups <= 0) { | ||
509 | dev_err(info->dev, "no groups defined\n"); | ||
510 | return -EINVAL; | ||
511 | } | ||
512 | func->groups = devm_kzalloc(info->dev, | ||
513 | func->num_groups * sizeof(char *), GFP_KERNEL); | ||
514 | |||
515 | for_each_child_of_node(np, child) { | ||
516 | func->groups[i] = child->name; | ||
517 | grp = &info->groups[grp_index++]; | ||
518 | ret = imx_pinctrl_parse_groups(child, grp, info, i++); | ||
519 | if (ret) | ||
520 | return ret; | ||
521 | } | ||
522 | |||
523 | return 0; | ||
524 | } | ||
525 | |||
526 | static int __devinit imx_pinctrl_probe_dt(struct platform_device *pdev, | ||
527 | struct imx_pinctrl_soc_info *info) | ||
528 | { | ||
529 | struct device_node *np = pdev->dev.of_node; | ||
530 | struct device_node *child; | ||
531 | int ret; | ||
532 | u32 nfuncs = 0; | ||
533 | u32 i = 0; | ||
534 | |||
535 | if (!np) | ||
536 | return -ENODEV; | ||
537 | |||
538 | nfuncs = of_get_child_count(np); | ||
539 | if (nfuncs <= 0) { | ||
540 | dev_err(&pdev->dev, "no functions defined\n"); | ||
541 | return -EINVAL; | ||
542 | } | ||
543 | |||
544 | info->nfunctions = nfuncs; | ||
545 | info->functions = devm_kzalloc(&pdev->dev, nfuncs * sizeof(struct imx_pmx_func), | ||
546 | GFP_KERNEL); | ||
547 | if (!info->functions) | ||
548 | return -ENOMEM; | ||
549 | |||
550 | info->ngroups = 0; | ||
551 | for_each_child_of_node(np, child) | ||
552 | info->ngroups += of_get_child_count(child); | ||
553 | info->groups = devm_kzalloc(&pdev->dev, info->ngroups * sizeof(struct imx_pin_group), | ||
554 | GFP_KERNEL); | ||
555 | if (!info->groups) | ||
556 | return -ENOMEM; | ||
557 | |||
558 | for_each_child_of_node(np, child) { | ||
559 | ret = imx_pinctrl_parse_functions(child, info, i++); | ||
560 | if (ret) { | ||
561 | dev_err(&pdev->dev, "failed to parse function\n"); | ||
562 | return ret; | ||
563 | } | ||
564 | } | ||
565 | |||
566 | return 0; | ||
567 | } | ||
568 | |||
569 | int __devinit imx_pinctrl_probe(struct platform_device *pdev, | ||
570 | struct imx_pinctrl_soc_info *info) | ||
571 | { | ||
572 | struct imx_pinctrl *ipctl; | ||
573 | struct resource *res; | ||
574 | int ret; | ||
575 | |||
576 | if (!info || !info->pins || !info->npins | ||
577 | || !info->pin_regs || !info->npin_regs) { | ||
578 | dev_err(&pdev->dev, "wrong pinctrl info\n"); | ||
579 | return -EINVAL; | ||
580 | } | ||
581 | info->dev = &pdev->dev; | ||
582 | |||
583 | /* Create state holders etc for this driver */ | ||
584 | ipctl = devm_kzalloc(&pdev->dev, sizeof(*ipctl), GFP_KERNEL); | ||
585 | if (!ipctl) | ||
586 | return -ENOMEM; | ||
587 | |||
588 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
589 | if (!res) | ||
590 | return -ENOENT; | ||
591 | |||
592 | ipctl->base = devm_request_and_ioremap(&pdev->dev, res); | ||
593 | if (!ipctl->base) | ||
594 | return -EBUSY; | ||
595 | |||
596 | imx_pinctrl_desc.name = dev_name(&pdev->dev); | ||
597 | imx_pinctrl_desc.pins = info->pins; | ||
598 | imx_pinctrl_desc.npins = info->npins; | ||
599 | |||
600 | ret = imx_pinctrl_probe_dt(pdev, info); | ||
601 | if (ret) { | ||
602 | dev_err(&pdev->dev, "fail to probe dt properties\n"); | ||
603 | return ret; | ||
604 | } | ||
605 | |||
606 | ipctl->info = info; | ||
607 | ipctl->dev = info->dev; | ||
608 | platform_set_drvdata(pdev, ipctl); | ||
609 | ipctl->pctl = pinctrl_register(&imx_pinctrl_desc, &pdev->dev, ipctl); | ||
610 | if (!ipctl->pctl) { | ||
611 | dev_err(&pdev->dev, "could not register IMX pinctrl driver\n"); | ||
612 | return -EINVAL; | ||
613 | } | ||
614 | |||
615 | dev_info(&pdev->dev, "initialized IMX pinctrl driver\n"); | ||
616 | |||
617 | return 0; | ||
618 | } | ||
619 | |||
620 | int __devexit imx_pinctrl_remove(struct platform_device *pdev) | ||
621 | { | ||
622 | struct imx_pinctrl *ipctl = platform_get_drvdata(pdev); | ||
623 | |||
624 | pinctrl_unregister(ipctl->pctl); | ||
625 | |||
626 | return 0; | ||
627 | } | ||