Commit 30612cd90005d8c4a3c53c7acadcf934a46c13df
Committed by
Linus Walleij
1 parent
c6ce2b6bff
Exists in
master
and in
16 other branches
pinctrl: imx1 core driver
Core driver for register formats of imx1/imx21/imx27 processors. The pins of those processors are grouped into ports. Each port has 32 pins. The pins mux configuration is controlled by registers with 1 or 2 bit per pin, depending on the specific control register. Signed-off-by: Markus Pargmann <mpa@pengutronix.de> Acked-by: Sascha Hauer <s.hauer@pengutronix.de> Acked-by: Shawn Guo <shawn.guo@linaro.org> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Showing 4 changed files with 732 additions and 0 deletions Side-by-side Diff
drivers/pinctrl/Kconfig
drivers/pinctrl/Makefile
... | ... | @@ -22,6 +22,7 @@ |
22 | 22 | obj-$(CONFIG_PINCTRL_BCM2835) += pinctrl-bcm2835.o |
23 | 23 | obj-$(CONFIG_PINCTRL_BAYTRAIL) += pinctrl-baytrail.o |
24 | 24 | obj-$(CONFIG_PINCTRL_IMX) += pinctrl-imx.o |
25 | +obj-$(CONFIG_PINCTRL_IMX1_CORE) += pinctrl-imx1-core.o | |
25 | 26 | obj-$(CONFIG_PINCTRL_IMX35) += pinctrl-imx35.o |
26 | 27 | obj-$(CONFIG_PINCTRL_IMX51) += pinctrl-imx51.o |
27 | 28 | obj-$(CONFIG_PINCTRL_IMX53) += pinctrl-imx53.o |
drivers/pinctrl/pinctrl-imx1-core.c
1 | +/* | |
2 | + * Core driver for the imx pin controller in imx1/21/27 | |
3 | + * | |
4 | + * Copyright (C) 2013 Pengutronix | |
5 | + * Author: Markus Pargmann <mpa@pengutronix.de> | |
6 | + * | |
7 | + * Based on pinctrl-imx.c: | |
8 | + * Author: Dong Aisheng <dong.aisheng@linaro.org> | |
9 | + * Copyright (C) 2012 Freescale Semiconductor, Inc. | |
10 | + * Copyright (C) 2012 Linaro Ltd. | |
11 | + * | |
12 | + * This program is free software; you can redistribute it and/or modify | |
13 | + * it under the terms of the GNU General Public License as published by | |
14 | + * the Free Software Foundation; either version 2 of the License, or | |
15 | + * (at your option) any later version. | |
16 | + */ | |
17 | + | |
18 | +#include <linux/bitops.h> | |
19 | +#include <linux/err.h> | |
20 | +#include <linux/init.h> | |
21 | +#include <linux/io.h> | |
22 | +#include <linux/module.h> | |
23 | +#include <linux/of.h> | |
24 | +#include <linux/of_device.h> | |
25 | +#include <linux/pinctrl/machine.h> | |
26 | +#include <linux/pinctrl/pinconf.h> | |
27 | +#include <linux/pinctrl/pinctrl.h> | |
28 | +#include <linux/pinctrl/pinmux.h> | |
29 | +#include <linux/slab.h> | |
30 | + | |
31 | +#include "core.h" | |
32 | +#include "pinctrl-imx1.h" | |
33 | + | |
34 | +struct imx1_pinctrl { | |
35 | + struct device *dev; | |
36 | + struct pinctrl_dev *pctl; | |
37 | + void __iomem *base; | |
38 | + const struct imx1_pinctrl_soc_info *info; | |
39 | +}; | |
40 | + | |
41 | +/* | |
42 | + * MX1 register offsets | |
43 | + */ | |
44 | + | |
45 | +#define MX1_DDIR 0x00 | |
46 | +#define MX1_OCR 0x04 | |
47 | +#define MX1_ICONFA 0x0c | |
48 | +#define MX1_ICONFB 0x10 | |
49 | +#define MX1_GIUS 0x20 | |
50 | +#define MX1_GPR 0x38 | |
51 | +#define MX1_PUEN 0x40 | |
52 | + | |
53 | +#define MX1_PORT_STRIDE 0x100 | |
54 | + | |
55 | + | |
56 | +/* | |
57 | + * MUX_ID format defines | |
58 | + */ | |
59 | +#define MX1_MUX_FUNCTION(val) (BIT(0) & val) | |
60 | +#define MX1_MUX_GPIO(val) ((BIT(1) & val) >> 1) | |
61 | +#define MX1_MUX_DIR(val) ((BIT(2) & val) >> 2) | |
62 | +#define MX1_MUX_OCONF(val) (((BIT(4) | BIT(5)) & val) >> 4) | |
63 | +#define MX1_MUX_ICONFA(val) (((BIT(8) | BIT(9)) & val) >> 8) | |
64 | +#define MX1_MUX_ICONFB(val) (((BIT(10) | BIT(11)) & val) >> 10) | |
65 | + | |
66 | + | |
67 | +/* | |
68 | + * IMX1 IOMUXC manages the pins based on ports. Each port has 32 pins. IOMUX | |
69 | + * control register are seperated into function, output configuration, input | |
70 | + * configuration A, input configuration B, GPIO in use and data direction. | |
71 | + * | |
72 | + * Those controls that are represented by 1 bit have a direct mapping between | |
73 | + * bit position and pin id. If they are represented by 2 bit, the lower 16 pins | |
74 | + * are in the first register and the upper 16 pins in the second (next) | |
75 | + * register. pin_id is stored in bit (pin_id%16)*2 and the bit above. | |
76 | + */ | |
77 | + | |
78 | +/* | |
79 | + * Calculates the register offset from a pin_id | |
80 | + */ | |
81 | +static void __iomem *imx1_mem(struct imx1_pinctrl *ipctl, unsigned int pin_id) | |
82 | +{ | |
83 | + unsigned int port = pin_id / 32; | |
84 | + return ipctl->base + port * MX1_PORT_STRIDE; | |
85 | +} | |
86 | + | |
87 | +/* | |
88 | + * Write to a register with 2 bits per pin. The function will automatically | |
89 | + * use the next register if the pin is managed in the second register. | |
90 | + */ | |
91 | +static void imx1_write_2bit(struct imx1_pinctrl *ipctl, unsigned int pin_id, | |
92 | + u32 value, u32 reg_offset) | |
93 | +{ | |
94 | + void __iomem *reg = imx1_mem(ipctl, pin_id) + reg_offset; | |
95 | + int offset = (pin_id % 16) * 2; /* offset, regardless of register used */ | |
96 | + int mask = ~(0x3 << offset); /* Mask for 2 bits at offset */ | |
97 | + u32 old_val; | |
98 | + u32 new_val; | |
99 | + | |
100 | + dev_dbg(ipctl->dev, "write: register 0x%p offset %d value 0x%x\n", | |
101 | + reg, offset, value); | |
102 | + | |
103 | + /* Use the next register if the pin's port pin number is >=16 */ | |
104 | + if (pin_id % 32 >= 16) | |
105 | + reg += 0x04; | |
106 | + | |
107 | + /* Get current state of pins */ | |
108 | + old_val = readl(reg); | |
109 | + old_val &= mask; | |
110 | + | |
111 | + new_val = value & 0x3; /* Make sure value is really 2 bit */ | |
112 | + new_val <<= offset; | |
113 | + new_val |= old_val;/* Set new state for pin_id */ | |
114 | + | |
115 | + writel(new_val, reg); | |
116 | +} | |
117 | + | |
118 | +static void imx1_write_bit(struct imx1_pinctrl *ipctl, unsigned int pin_id, | |
119 | + u32 value, u32 reg_offset) | |
120 | +{ | |
121 | + void __iomem *reg = imx1_mem(ipctl, pin_id) + reg_offset; | |
122 | + int offset = pin_id % 32; | |
123 | + int mask = ~BIT_MASK(offset); | |
124 | + u32 old_val; | |
125 | + u32 new_val; | |
126 | + | |
127 | + /* Get current state of pins */ | |
128 | + old_val = readl(reg); | |
129 | + old_val &= mask; | |
130 | + | |
131 | + new_val = value & 0x1; /* Make sure value is really 1 bit */ | |
132 | + new_val <<= offset; | |
133 | + new_val |= old_val;/* Set new state for pin_id */ | |
134 | + | |
135 | + writel(new_val, reg); | |
136 | +} | |
137 | + | |
138 | +static int imx1_read_2bit(struct imx1_pinctrl *ipctl, unsigned int pin_id, | |
139 | + u32 reg_offset) | |
140 | +{ | |
141 | + void __iomem *reg = imx1_mem(ipctl, pin_id) + reg_offset; | |
142 | + int offset = pin_id % 16; | |
143 | + | |
144 | + /* Use the next register if the pin's port pin number is >=16 */ | |
145 | + if (pin_id % 32 >= 16) | |
146 | + reg += 0x04; | |
147 | + | |
148 | + return (readl(reg) & (BIT(offset) | BIT(offset+1))) >> offset; | |
149 | +} | |
150 | + | |
151 | +static int imx1_read_bit(struct imx1_pinctrl *ipctl, unsigned int pin_id, | |
152 | + u32 reg_offset) | |
153 | +{ | |
154 | + void __iomem *reg = imx1_mem(ipctl, pin_id) + reg_offset; | |
155 | + int offset = pin_id % 32; | |
156 | + | |
157 | + return !!(readl(reg) & BIT(offset)); | |
158 | +} | |
159 | + | |
160 | +static const inline struct imx1_pin_group *imx1_pinctrl_find_group_by_name( | |
161 | + const struct imx1_pinctrl_soc_info *info, | |
162 | + const char *name) | |
163 | +{ | |
164 | + const struct imx1_pin_group *grp = NULL; | |
165 | + int i; | |
166 | + | |
167 | + for (i = 0; i < info->ngroups; i++) { | |
168 | + if (!strcmp(info->groups[i].name, name)) { | |
169 | + grp = &info->groups[i]; | |
170 | + break; | |
171 | + } | |
172 | + } | |
173 | + | |
174 | + return grp; | |
175 | +} | |
176 | + | |
177 | +static int imx1_get_groups_count(struct pinctrl_dev *pctldev) | |
178 | +{ | |
179 | + struct imx1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); | |
180 | + const struct imx1_pinctrl_soc_info *info = ipctl->info; | |
181 | + | |
182 | + return info->ngroups; | |
183 | +} | |
184 | + | |
185 | +static const char *imx1_get_group_name(struct pinctrl_dev *pctldev, | |
186 | + unsigned selector) | |
187 | +{ | |
188 | + struct imx1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); | |
189 | + const struct imx1_pinctrl_soc_info *info = ipctl->info; | |
190 | + | |
191 | + return info->groups[selector].name; | |
192 | +} | |
193 | + | |
194 | +static int imx1_get_group_pins(struct pinctrl_dev *pctldev, unsigned selector, | |
195 | + const unsigned int **pins, | |
196 | + unsigned *npins) | |
197 | +{ | |
198 | + struct imx1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); | |
199 | + const struct imx1_pinctrl_soc_info *info = ipctl->info; | |
200 | + | |
201 | + if (selector >= info->ngroups) | |
202 | + return -EINVAL; | |
203 | + | |
204 | + *pins = info->groups[selector].pin_ids; | |
205 | + *npins = info->groups[selector].npins; | |
206 | + | |
207 | + return 0; | |
208 | +} | |
209 | + | |
210 | +static void imx1_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s, | |
211 | + unsigned offset) | |
212 | +{ | |
213 | + struct imx1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); | |
214 | + | |
215 | + seq_printf(s, "GPIO %d, function %d, direction %d, oconf %d, iconfa %d, iconfb %d", | |
216 | + imx1_read_bit(ipctl, offset, MX1_GIUS), | |
217 | + imx1_read_bit(ipctl, offset, MX1_GPR), | |
218 | + imx1_read_bit(ipctl, offset, MX1_DDIR), | |
219 | + imx1_read_2bit(ipctl, offset, MX1_OCR), | |
220 | + imx1_read_2bit(ipctl, offset, MX1_ICONFA), | |
221 | + imx1_read_2bit(ipctl, offset, MX1_ICONFB)); | |
222 | +} | |
223 | + | |
224 | +static int imx1_dt_node_to_map(struct pinctrl_dev *pctldev, | |
225 | + struct device_node *np, | |
226 | + struct pinctrl_map **map, unsigned *num_maps) | |
227 | +{ | |
228 | + struct imx1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); | |
229 | + const struct imx1_pinctrl_soc_info *info = ipctl->info; | |
230 | + const struct imx1_pin_group *grp; | |
231 | + struct pinctrl_map *new_map; | |
232 | + struct device_node *parent; | |
233 | + int map_num = 1; | |
234 | + int i, j; | |
235 | + | |
236 | + /* | |
237 | + * first find the group of this node and check if we need create | |
238 | + * config maps for pins | |
239 | + */ | |
240 | + grp = imx1_pinctrl_find_group_by_name(info, np->name); | |
241 | + if (!grp) { | |
242 | + dev_err(info->dev, "unable to find group for node %s\n", | |
243 | + np->name); | |
244 | + return -EINVAL; | |
245 | + } | |
246 | + | |
247 | + for (i = 0; i < grp->npins; i++) | |
248 | + map_num++; | |
249 | + | |
250 | + new_map = kmalloc(sizeof(struct pinctrl_map) * map_num, GFP_KERNEL); | |
251 | + if (!new_map) | |
252 | + return -ENOMEM; | |
253 | + | |
254 | + *map = new_map; | |
255 | + *num_maps = map_num; | |
256 | + | |
257 | + /* create mux map */ | |
258 | + parent = of_get_parent(np); | |
259 | + if (!parent) { | |
260 | + kfree(new_map); | |
261 | + return -EINVAL; | |
262 | + } | |
263 | + new_map[0].type = PIN_MAP_TYPE_MUX_GROUP; | |
264 | + new_map[0].data.mux.function = parent->name; | |
265 | + new_map[0].data.mux.group = np->name; | |
266 | + of_node_put(parent); | |
267 | + | |
268 | + /* create config map */ | |
269 | + new_map++; | |
270 | + for (i = j = 0; i < grp->npins; i++) { | |
271 | + new_map[j].type = PIN_MAP_TYPE_CONFIGS_PIN; | |
272 | + new_map[j].data.configs.group_or_pin = | |
273 | + pin_get_name(pctldev, grp->pins[i].pin_id); | |
274 | + new_map[j].data.configs.configs = &grp->pins[i].config; | |
275 | + new_map[j].data.configs.num_configs = 1; | |
276 | + j++; | |
277 | + } | |
278 | + | |
279 | + dev_dbg(pctldev->dev, "maps: function %s group %s num %d\n", | |
280 | + (*map)->data.mux.function, (*map)->data.mux.group, map_num); | |
281 | + | |
282 | + return 0; | |
283 | +} | |
284 | + | |
285 | +static void imx1_dt_free_map(struct pinctrl_dev *pctldev, | |
286 | + struct pinctrl_map *map, unsigned num_maps) | |
287 | +{ | |
288 | + kfree(map); | |
289 | +} | |
290 | + | |
291 | +static const struct pinctrl_ops imx1_pctrl_ops = { | |
292 | + .get_groups_count = imx1_get_groups_count, | |
293 | + .get_group_name = imx1_get_group_name, | |
294 | + .get_group_pins = imx1_get_group_pins, | |
295 | + .pin_dbg_show = imx1_pin_dbg_show, | |
296 | + .dt_node_to_map = imx1_dt_node_to_map, | |
297 | + .dt_free_map = imx1_dt_free_map, | |
298 | + | |
299 | +}; | |
300 | + | |
301 | +static int imx1_pmx_enable(struct pinctrl_dev *pctldev, unsigned selector, | |
302 | + unsigned group) | |
303 | +{ | |
304 | + struct imx1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); | |
305 | + const struct imx1_pinctrl_soc_info *info = ipctl->info; | |
306 | + const struct imx1_pin *pins; | |
307 | + unsigned int npins; | |
308 | + int i; | |
309 | + | |
310 | + /* | |
311 | + * Configure the mux mode for each pin in the group for a specific | |
312 | + * function. | |
313 | + */ | |
314 | + pins = info->groups[group].pins; | |
315 | + npins = info->groups[group].npins; | |
316 | + | |
317 | + WARN_ON(!pins || !npins); | |
318 | + | |
319 | + dev_dbg(ipctl->dev, "enable function %s group %s\n", | |
320 | + info->functions[selector].name, info->groups[group].name); | |
321 | + | |
322 | + for (i = 0; i < npins; i++) { | |
323 | + unsigned int mux = pins[i].mux_id; | |
324 | + unsigned int pin_id = pins[i].pin_id; | |
325 | + unsigned int afunction = MX1_MUX_FUNCTION(mux); | |
326 | + unsigned int gpio_in_use = MX1_MUX_GPIO(mux); | |
327 | + unsigned int direction = MX1_MUX_DIR(mux); | |
328 | + unsigned int gpio_oconf = MX1_MUX_OCONF(mux); | |
329 | + unsigned int gpio_iconfa = MX1_MUX_ICONFA(mux); | |
330 | + unsigned int gpio_iconfb = MX1_MUX_ICONFB(mux); | |
331 | + | |
332 | + dev_dbg(pctldev->dev, "%s, pin 0x%x, function %d, gpio %d, direction %d, oconf %d, iconfa %d, iconfb %d\n", | |
333 | + __func__, pin_id, afunction, gpio_in_use, | |
334 | + direction, gpio_oconf, gpio_iconfa, | |
335 | + gpio_iconfb); | |
336 | + | |
337 | + imx1_write_bit(ipctl, pin_id, gpio_in_use, MX1_GIUS); | |
338 | + imx1_write_bit(ipctl, pin_id, direction, MX1_DDIR); | |
339 | + | |
340 | + if (gpio_in_use) { | |
341 | + imx1_write_2bit(ipctl, pin_id, gpio_oconf, MX1_OCR); | |
342 | + imx1_write_2bit(ipctl, pin_id, gpio_iconfa, | |
343 | + MX1_ICONFA); | |
344 | + imx1_write_2bit(ipctl, pin_id, gpio_iconfb, | |
345 | + MX1_ICONFB); | |
346 | + } else { | |
347 | + imx1_write_bit(ipctl, pin_id, afunction, MX1_GPR); | |
348 | + } | |
349 | + } | |
350 | + | |
351 | + return 0; | |
352 | +} | |
353 | + | |
354 | +static int imx1_pmx_get_funcs_count(struct pinctrl_dev *pctldev) | |
355 | +{ | |
356 | + struct imx1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); | |
357 | + const struct imx1_pinctrl_soc_info *info = ipctl->info; | |
358 | + | |
359 | + return info->nfunctions; | |
360 | +} | |
361 | + | |
362 | +static const char *imx1_pmx_get_func_name(struct pinctrl_dev *pctldev, | |
363 | + unsigned selector) | |
364 | +{ | |
365 | + struct imx1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); | |
366 | + const struct imx1_pinctrl_soc_info *info = ipctl->info; | |
367 | + | |
368 | + return info->functions[selector].name; | |
369 | +} | |
370 | + | |
371 | +static int imx1_pmx_get_groups(struct pinctrl_dev *pctldev, unsigned selector, | |
372 | + const char * const **groups, | |
373 | + unsigned * const num_groups) | |
374 | +{ | |
375 | + struct imx1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); | |
376 | + const struct imx1_pinctrl_soc_info *info = ipctl->info; | |
377 | + | |
378 | + *groups = info->functions[selector].groups; | |
379 | + *num_groups = info->functions[selector].num_groups; | |
380 | + | |
381 | + return 0; | |
382 | +} | |
383 | + | |
384 | +static const struct pinmux_ops imx1_pmx_ops = { | |
385 | + .get_functions_count = imx1_pmx_get_funcs_count, | |
386 | + .get_function_name = imx1_pmx_get_func_name, | |
387 | + .get_function_groups = imx1_pmx_get_groups, | |
388 | + .enable = imx1_pmx_enable, | |
389 | +}; | |
390 | + | |
391 | +static int imx1_pinconf_get(struct pinctrl_dev *pctldev, | |
392 | + unsigned pin_id, unsigned long *config) | |
393 | +{ | |
394 | + struct imx1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); | |
395 | + | |
396 | + *config = imx1_read_bit(ipctl, pin_id, MX1_PUEN); | |
397 | + | |
398 | + return 0; | |
399 | +} | |
400 | + | |
401 | +static int imx1_pinconf_set(struct pinctrl_dev *pctldev, | |
402 | + unsigned pin_id, unsigned long *configs, | |
403 | + unsigned num_configs) | |
404 | +{ | |
405 | + struct imx1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); | |
406 | + const struct imx1_pinctrl_soc_info *info = ipctl->info; | |
407 | + int i; | |
408 | + | |
409 | + for (i = 0; i != num_configs; ++i) { | |
410 | + imx1_write_bit(ipctl, pin_id, configs[i] & 0x01, MX1_PUEN); | |
411 | + | |
412 | + dev_dbg(ipctl->dev, "pinconf set pullup pin %s\n", | |
413 | + info->pins[pin_id].name); | |
414 | + } | |
415 | + | |
416 | + return 0; | |
417 | +} | |
418 | + | |
419 | +static void imx1_pinconf_dbg_show(struct pinctrl_dev *pctldev, | |
420 | + struct seq_file *s, unsigned pin_id) | |
421 | +{ | |
422 | + unsigned long config; | |
423 | + | |
424 | + imx1_pinconf_get(pctldev, pin_id, &config); | |
425 | + seq_printf(s, "0x%lx", config); | |
426 | +} | |
427 | + | |
428 | +static void imx1_pinconf_group_dbg_show(struct pinctrl_dev *pctldev, | |
429 | + struct seq_file *s, unsigned group) | |
430 | +{ | |
431 | + struct imx1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); | |
432 | + const struct imx1_pinctrl_soc_info *info = ipctl->info; | |
433 | + struct imx1_pin_group *grp; | |
434 | + unsigned long config; | |
435 | + const char *name; | |
436 | + int i, ret; | |
437 | + | |
438 | + if (group > info->ngroups) | |
439 | + return; | |
440 | + | |
441 | + seq_puts(s, "\n"); | |
442 | + grp = &info->groups[group]; | |
443 | + for (i = 0; i < grp->npins; i++) { | |
444 | + name = pin_get_name(pctldev, grp->pins[i].pin_id); | |
445 | + ret = imx1_pinconf_get(pctldev, grp->pins[i].pin_id, &config); | |
446 | + if (ret) | |
447 | + return; | |
448 | + seq_printf(s, "%s: 0x%lx", name, config); | |
449 | + } | |
450 | +} | |
451 | + | |
452 | +static const struct pinconf_ops imx1_pinconf_ops = { | |
453 | + .pin_config_get = imx1_pinconf_get, | |
454 | + .pin_config_set = imx1_pinconf_set, | |
455 | + .pin_config_dbg_show = imx1_pinconf_dbg_show, | |
456 | + .pin_config_group_dbg_show = imx1_pinconf_group_dbg_show, | |
457 | +}; | |
458 | + | |
459 | +static struct pinctrl_desc imx1_pinctrl_desc = { | |
460 | + .pctlops = &imx1_pctrl_ops, | |
461 | + .pmxops = &imx1_pmx_ops, | |
462 | + .confops = &imx1_pinconf_ops, | |
463 | + .owner = THIS_MODULE, | |
464 | +}; | |
465 | + | |
466 | +static int imx1_pinctrl_parse_groups(struct device_node *np, | |
467 | + struct imx1_pin_group *grp, | |
468 | + struct imx1_pinctrl_soc_info *info, | |
469 | + u32 index) | |
470 | +{ | |
471 | + int size; | |
472 | + const __be32 *list; | |
473 | + int i; | |
474 | + | |
475 | + dev_dbg(info->dev, "group(%d): %s\n", index, np->name); | |
476 | + | |
477 | + /* Initialise group */ | |
478 | + grp->name = np->name; | |
479 | + | |
480 | + /* | |
481 | + * the binding format is fsl,pins = <PIN MUX_ID CONFIG> | |
482 | + */ | |
483 | + list = of_get_property(np, "fsl,pins", &size); | |
484 | + /* we do not check return since it's safe node passed down */ | |
485 | + if (!size || size % 12) { | |
486 | + dev_notice(info->dev, "Not a valid fsl,pins property (%s)\n", | |
487 | + np->name); | |
488 | + return -EINVAL; | |
489 | + } | |
490 | + | |
491 | + grp->npins = size / 12; | |
492 | + grp->pins = devm_kzalloc(info->dev, | |
493 | + grp->npins * sizeof(struct imx1_pin), GFP_KERNEL); | |
494 | + grp->pin_ids = devm_kzalloc(info->dev, | |
495 | + grp->npins * sizeof(unsigned int), GFP_KERNEL); | |
496 | + | |
497 | + if (!grp->pins || !grp->pin_ids) | |
498 | + return -ENOMEM; | |
499 | + | |
500 | + for (i = 0; i < grp->npins; i++) { | |
501 | + grp->pins[i].pin_id = be32_to_cpu(*list++); | |
502 | + grp->pins[i].mux_id = be32_to_cpu(*list++); | |
503 | + grp->pins[i].config = be32_to_cpu(*list++); | |
504 | + | |
505 | + grp->pin_ids[i] = grp->pins[i].pin_id; | |
506 | + } | |
507 | + | |
508 | + return 0; | |
509 | +} | |
510 | + | |
511 | +static int imx1_pinctrl_parse_functions(struct device_node *np, | |
512 | + struct imx1_pinctrl_soc_info *info, | |
513 | + u32 index) | |
514 | +{ | |
515 | + struct device_node *child; | |
516 | + struct imx1_pmx_func *func; | |
517 | + struct imx1_pin_group *grp; | |
518 | + int ret; | |
519 | + static u32 grp_index; | |
520 | + u32 i = 0; | |
521 | + | |
522 | + dev_dbg(info->dev, "parse function(%d): %s\n", index, np->name); | |
523 | + | |
524 | + func = &info->functions[index]; | |
525 | + | |
526 | + /* Initialise function */ | |
527 | + func->name = np->name; | |
528 | + func->num_groups = of_get_child_count(np); | |
529 | + if (func->num_groups <= 0) | |
530 | + return -EINVAL; | |
531 | + | |
532 | + func->groups = devm_kzalloc(info->dev, | |
533 | + func->num_groups * sizeof(char *), GFP_KERNEL); | |
534 | + | |
535 | + if (!func->groups) | |
536 | + return -ENOMEM; | |
537 | + | |
538 | + for_each_child_of_node(np, child) { | |
539 | + func->groups[i] = child->name; | |
540 | + grp = &info->groups[grp_index++]; | |
541 | + ret = imx1_pinctrl_parse_groups(child, grp, info, i++); | |
542 | + if (ret == -ENOMEM) | |
543 | + return ret; | |
544 | + } | |
545 | + | |
546 | + return 0; | |
547 | +} | |
548 | + | |
549 | +static int imx1_pinctrl_parse_dt(struct platform_device *pdev, | |
550 | + struct imx1_pinctrl *pctl, struct imx1_pinctrl_soc_info *info) | |
551 | +{ | |
552 | + struct device_node *np = pdev->dev.of_node; | |
553 | + struct device_node *child; | |
554 | + int ret; | |
555 | + u32 nfuncs = 0; | |
556 | + u32 ngroups = 0; | |
557 | + u32 ifunc = 0; | |
558 | + | |
559 | + if (!np) | |
560 | + return -ENODEV; | |
561 | + | |
562 | + for_each_child_of_node(np, child) { | |
563 | + ++nfuncs; | |
564 | + ngroups += of_get_child_count(child); | |
565 | + } | |
566 | + | |
567 | + if (!nfuncs) { | |
568 | + dev_err(&pdev->dev, "No pin functions defined\n"); | |
569 | + return -EINVAL; | |
570 | + } | |
571 | + | |
572 | + info->nfunctions = nfuncs; | |
573 | + info->functions = devm_kzalloc(&pdev->dev, | |
574 | + nfuncs * sizeof(struct imx1_pmx_func), GFP_KERNEL); | |
575 | + | |
576 | + info->ngroups = ngroups; | |
577 | + info->groups = devm_kzalloc(&pdev->dev, | |
578 | + ngroups * sizeof(struct imx1_pin_group), GFP_KERNEL); | |
579 | + | |
580 | + | |
581 | + if (!info->functions || !info->groups) | |
582 | + return -ENOMEM; | |
583 | + | |
584 | + for_each_child_of_node(np, child) { | |
585 | + ret = imx1_pinctrl_parse_functions(child, info, ifunc++); | |
586 | + if (ret == -ENOMEM) | |
587 | + return -ENOMEM; | |
588 | + } | |
589 | + | |
590 | + return 0; | |
591 | +} | |
592 | + | |
593 | +int imx1_pinctrl_core_probe(struct platform_device *pdev, | |
594 | + struct imx1_pinctrl_soc_info *info) | |
595 | +{ | |
596 | + struct imx1_pinctrl *ipctl; | |
597 | + struct resource *res; | |
598 | + struct pinctrl_desc *pctl_desc; | |
599 | + int ret; | |
600 | + | |
601 | + if (!info || !info->pins || !info->npins) { | |
602 | + dev_err(&pdev->dev, "wrong pinctrl info\n"); | |
603 | + return -EINVAL; | |
604 | + } | |
605 | + info->dev = &pdev->dev; | |
606 | + | |
607 | + /* Create state holders etc for this driver */ | |
608 | + ipctl = devm_kzalloc(&pdev->dev, sizeof(*ipctl), GFP_KERNEL); | |
609 | + if (!ipctl) | |
610 | + return -ENOMEM; | |
611 | + | |
612 | + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | |
613 | + if (!res) | |
614 | + return -ENOENT; | |
615 | + | |
616 | + ipctl->base = devm_ioremap_nocache(&pdev->dev, res->start, | |
617 | + resource_size(res)); | |
618 | + if (IS_ERR(ipctl->base)) | |
619 | + return PTR_ERR(ipctl->base); | |
620 | + | |
621 | + pctl_desc = &imx1_pinctrl_desc; | |
622 | + pctl_desc->name = dev_name(&pdev->dev); | |
623 | + pctl_desc->pins = info->pins; | |
624 | + pctl_desc->npins = info->npins; | |
625 | + | |
626 | + ret = imx1_pinctrl_parse_dt(pdev, ipctl, info); | |
627 | + if (ret) { | |
628 | + dev_err(&pdev->dev, "fail to probe dt properties\n"); | |
629 | + return ret; | |
630 | + } | |
631 | + | |
632 | + ipctl->info = info; | |
633 | + ipctl->dev = info->dev; | |
634 | + platform_set_drvdata(pdev, ipctl); | |
635 | + ipctl->pctl = pinctrl_register(pctl_desc, &pdev->dev, ipctl); | |
636 | + if (!ipctl->pctl) { | |
637 | + dev_err(&pdev->dev, "could not register IMX pinctrl driver\n"); | |
638 | + return -EINVAL; | |
639 | + } | |
640 | + | |
641 | + dev_info(&pdev->dev, "initialized IMX pinctrl driver\n"); | |
642 | + | |
643 | + return 0; | |
644 | +} | |
645 | + | |
646 | +int imx1_pinctrl_core_remove(struct platform_device *pdev) | |
647 | +{ | |
648 | + struct imx1_pinctrl *ipctl = platform_get_drvdata(pdev); | |
649 | + | |
650 | + pinctrl_unregister(ipctl->pctl); | |
651 | + | |
652 | + return 0; | |
653 | +} |
drivers/pinctrl/pinctrl-imx1.h
1 | +/* | |
2 | + * IMX pinmux core definitions | |
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 | +#ifndef __DRIVERS_PINCTRL_IMX1_H | |
16 | +#define __DRIVERS_PINCTRL_IMX1_H | |
17 | + | |
18 | +struct platform_device; | |
19 | + | |
20 | +/** | |
21 | + * struct imx1_pin - describes an IMX1/21/27 pin. | |
22 | + * @pin_id: ID of the described pin. | |
23 | + * @mux_id: ID of the mux setup. | |
24 | + * @config: Configuration of the pin (currently only pullup-enable). | |
25 | + */ | |
26 | +struct imx1_pin { | |
27 | + unsigned int pin_id; | |
28 | + unsigned int mux_id; | |
29 | + unsigned long config; | |
30 | +}; | |
31 | + | |
32 | +/** | |
33 | + * struct imx1_pin_group - describes an IMX pin group | |
34 | + * @name: the name of this specific pin group | |
35 | + * @pins: an array of imx1_pin structs used in this group | |
36 | + * @npins: the number of pins in this group array, i.e. the number of | |
37 | + * elements in .pins so we can iterate over that array | |
38 | + */ | |
39 | +struct imx1_pin_group { | |
40 | + const char *name; | |
41 | + unsigned int *pin_ids; | |
42 | + struct imx1_pin *pins; | |
43 | + unsigned npins; | |
44 | +}; | |
45 | + | |
46 | +/** | |
47 | + * struct imx1_pmx_func - describes IMX pinmux functions | |
48 | + * @name: the name of this specific function | |
49 | + * @groups: corresponding pin groups | |
50 | + * @num_groups: the number of groups | |
51 | + */ | |
52 | +struct imx1_pmx_func { | |
53 | + const char *name; | |
54 | + const char **groups; | |
55 | + unsigned num_groups; | |
56 | +}; | |
57 | + | |
58 | +struct imx1_pinctrl_soc_info { | |
59 | + struct device *dev; | |
60 | + const struct pinctrl_pin_desc *pins; | |
61 | + unsigned int npins; | |
62 | + struct imx1_pin_group *groups; | |
63 | + unsigned int ngroups; | |
64 | + struct imx1_pmx_func *functions; | |
65 | + unsigned int nfunctions; | |
66 | +}; | |
67 | + | |
68 | +#define IMX_PINCTRL_PIN(pin) PINCTRL_PIN(pin, #pin) | |
69 | + | |
70 | +int imx1_pinctrl_core_probe(struct platform_device *pdev, | |
71 | + struct imx1_pinctrl_soc_info *info); | |
72 | +int imx1_pinctrl_core_remove(struct platform_device *pdev); | |
73 | +#endif /* __DRIVERS_PINCTRL_IMX1_H */ |