]>
Commit | Line | Data |
---|---|---|
971dac71 SW |
1 | /* |
2 | * Driver for the NVIDIA Tegra pinmux | |
3 | * | |
4 | * Copyright (c) 2011, NVIDIA CORPORATION. All rights reserved. | |
5 | * | |
6 | * Derived from code: | |
7 | * Copyright (C) 2010 Google, Inc. | |
8 | * Copyright (C) 2010 NVIDIA Corporation | |
9 | * Copyright (C) 2009-2011 ST-Ericsson AB | |
10 | * | |
11 | * This program is free software; you can redistribute it and/or modify it | |
12 | * under the terms and conditions of the GNU General Public License, | |
13 | * version 2, as published by the Free Software Foundation. | |
14 | * | |
15 | * This program is distributed in the hope it will be useful, but WITHOUT | |
16 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
17 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
18 | * more details. | |
19 | */ | |
20 | ||
21 | #include <linux/err.h> | |
22 | #include <linux/init.h> | |
23 | #include <linux/io.h> | |
24 | #include <linux/module.h> | |
25 | #include <linux/of_device.h> | |
60f7f500 | 26 | #include <linux/pinctrl/machine.h> |
971dac71 SW |
27 | #include <linux/pinctrl/pinctrl.h> |
28 | #include <linux/pinctrl/pinmux.h> | |
29 | #include <linux/pinctrl/pinconf.h> | |
60f7f500 | 30 | #include <linux/slab.h> |
971dac71 SW |
31 | |
32 | #include <mach/pinconf-tegra.h> | |
33 | ||
34 | #include "pinctrl-tegra.h" | |
35 | ||
36 | #define DRIVER_NAME "tegra-pinmux-disabled" | |
37 | ||
38 | struct tegra_pmx { | |
39 | struct device *dev; | |
40 | struct pinctrl_dev *pctl; | |
41 | ||
42 | const struct tegra_pinctrl_soc_data *soc; | |
43 | ||
44 | int nbanks; | |
45 | void __iomem **regs; | |
46 | }; | |
47 | ||
48 | static inline u32 pmx_readl(struct tegra_pmx *pmx, u32 bank, u32 reg) | |
49 | { | |
50 | return readl(pmx->regs[bank] + reg); | |
51 | } | |
52 | ||
53 | static inline void pmx_writel(struct tegra_pmx *pmx, u32 val, u32 bank, u32 reg) | |
54 | { | |
55 | writel(val, pmx->regs[bank] + reg); | |
56 | } | |
57 | ||
d1e90e9e | 58 | static int tegra_pinctrl_get_groups_count(struct pinctrl_dev *pctldev) |
971dac71 SW |
59 | { |
60 | struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); | |
61 | ||
d1e90e9e | 62 | return pmx->soc->ngroups; |
971dac71 SW |
63 | } |
64 | ||
65 | static const char *tegra_pinctrl_get_group_name(struct pinctrl_dev *pctldev, | |
66 | unsigned group) | |
67 | { | |
68 | struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); | |
69 | ||
971dac71 SW |
70 | return pmx->soc->groups[group].name; |
71 | } | |
72 | ||
73 | static int tegra_pinctrl_get_group_pins(struct pinctrl_dev *pctldev, | |
74 | unsigned group, | |
75 | const unsigned **pins, | |
76 | unsigned *num_pins) | |
77 | { | |
78 | struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); | |
79 | ||
971dac71 SW |
80 | *pins = pmx->soc->groups[group].pins; |
81 | *num_pins = pmx->soc->groups[group].npins; | |
82 | ||
83 | return 0; | |
84 | } | |
85 | ||
86 | static void tegra_pinctrl_pin_dbg_show(struct pinctrl_dev *pctldev, | |
87 | struct seq_file *s, | |
88 | unsigned offset) | |
89 | { | |
90 | seq_printf(s, " " DRIVER_NAME); | |
91 | } | |
92 | ||
60f7f500 SW |
93 | static int reserve_map(struct pinctrl_map **map, unsigned *reserved_maps, |
94 | unsigned *num_maps, unsigned reserve) | |
95 | { | |
96 | unsigned old_num = *reserved_maps; | |
97 | unsigned new_num = *num_maps + reserve; | |
98 | struct pinctrl_map *new_map; | |
99 | ||
100 | if (old_num >= new_num) | |
101 | return 0; | |
102 | ||
103 | new_map = krealloc(*map, sizeof(*new_map) * new_num, GFP_KERNEL); | |
104 | if (!new_map) | |
105 | return -ENOMEM; | |
106 | ||
107 | memset(new_map + old_num, 0, (new_num - old_num) * sizeof(*new_map)); | |
108 | ||
109 | *map = new_map; | |
110 | *reserved_maps = new_num; | |
111 | ||
112 | return 0; | |
113 | } | |
114 | ||
115 | static int add_map_mux(struct pinctrl_map **map, unsigned *reserved_maps, | |
116 | unsigned *num_maps, const char *group, | |
117 | const char *function) | |
118 | { | |
119 | if (*num_maps == *reserved_maps) | |
120 | return -ENOSPC; | |
121 | ||
122 | (*map)[*num_maps].type = PIN_MAP_TYPE_MUX_GROUP; | |
123 | (*map)[*num_maps].data.mux.group = group; | |
124 | (*map)[*num_maps].data.mux.function = function; | |
125 | (*num_maps)++; | |
126 | ||
127 | return 0; | |
128 | } | |
129 | ||
130 | static int add_map_configs(struct pinctrl_map **map, unsigned *reserved_maps, | |
131 | unsigned *num_maps, const char *group, | |
132 | unsigned long *configs, unsigned num_configs) | |
133 | { | |
134 | unsigned long *dup_configs; | |
135 | ||
136 | if (*num_maps == *reserved_maps) | |
137 | return -ENOSPC; | |
138 | ||
139 | dup_configs = kmemdup(configs, num_configs * sizeof(*dup_configs), | |
140 | GFP_KERNEL); | |
141 | if (!dup_configs) | |
142 | return -ENOMEM; | |
143 | ||
144 | (*map)[*num_maps].type = PIN_MAP_TYPE_CONFIGS_GROUP; | |
145 | (*map)[*num_maps].data.configs.group_or_pin = group; | |
146 | (*map)[*num_maps].data.configs.configs = dup_configs; | |
147 | (*map)[*num_maps].data.configs.num_configs = num_configs; | |
148 | (*num_maps)++; | |
149 | ||
150 | return 0; | |
151 | } | |
152 | ||
153 | static int add_config(unsigned long **configs, unsigned *num_configs, | |
154 | unsigned long config) | |
155 | { | |
156 | unsigned old_num = *num_configs; | |
157 | unsigned new_num = old_num + 1; | |
158 | unsigned long *new_configs; | |
159 | ||
160 | new_configs = krealloc(*configs, sizeof(*new_configs) * new_num, | |
161 | GFP_KERNEL); | |
162 | if (!new_configs) | |
163 | return -ENOMEM; | |
164 | ||
165 | new_configs[old_num] = config; | |
166 | ||
167 | *configs = new_configs; | |
168 | *num_configs = new_num; | |
169 | ||
170 | return 0; | |
171 | } | |
172 | ||
173 | void tegra_pinctrl_dt_free_map(struct pinctrl_dev *pctldev, | |
174 | struct pinctrl_map *map, unsigned num_maps) | |
175 | { | |
176 | int i; | |
177 | ||
178 | for (i = 0; i < num_maps; i++) | |
179 | if (map[i].type == PIN_MAP_TYPE_CONFIGS_GROUP) | |
180 | kfree(map[i].data.configs.configs); | |
181 | ||
182 | kfree(map); | |
183 | } | |
184 | ||
185 | static const struct cfg_param { | |
186 | const char *property; | |
187 | enum tegra_pinconf_param param; | |
188 | } cfg_params[] = { | |
189 | {"nvidia,pull", TEGRA_PINCONF_PARAM_PULL}, | |
190 | {"nvidia,tristate", TEGRA_PINCONF_PARAM_TRISTATE}, | |
191 | {"nvidia,enable-input", TEGRA_PINCONF_PARAM_ENABLE_INPUT}, | |
192 | {"nvidia,open-drain", TEGRA_PINCONF_PARAM_OPEN_DRAIN}, | |
193 | {"nvidia,lock", TEGRA_PINCONF_PARAM_LOCK}, | |
194 | {"nvidia,io-reset", TEGRA_PINCONF_PARAM_IORESET}, | |
195 | {"nvidia,high-speed-mode", TEGRA_PINCONF_PARAM_HIGH_SPEED_MODE}, | |
196 | {"nvidia,schmitt", TEGRA_PINCONF_PARAM_SCHMITT}, | |
197 | {"nvidia,low-power-mode", TEGRA_PINCONF_PARAM_LOW_POWER_MODE}, | |
198 | {"nvidia,pull-down-strength", TEGRA_PINCONF_PARAM_DRIVE_DOWN_STRENGTH}, | |
199 | {"nvidia,pull-up-strength", TEGRA_PINCONF_PARAM_DRIVE_UP_STRENGTH}, | |
200 | {"nvidia,slew-rate-falling", TEGRA_PINCONF_PARAM_SLEW_RATE_FALLING}, | |
201 | {"nvidia,slew-rate-rising", TEGRA_PINCONF_PARAM_SLEW_RATE_RISING}, | |
202 | }; | |
203 | ||
204 | int tegra_pinctrl_dt_subnode_to_map(struct device_node *np, | |
205 | struct pinctrl_map **map, | |
206 | unsigned *reserved_maps, | |
207 | unsigned *num_maps) | |
208 | { | |
209 | int ret, i; | |
210 | const char *function; | |
211 | u32 val; | |
212 | unsigned long config; | |
213 | unsigned long *configs = NULL; | |
214 | unsigned num_configs = 0; | |
215 | unsigned reserve; | |
216 | struct property *prop; | |
217 | const char *group; | |
218 | ||
219 | ret = of_property_read_string(np, "nvidia,function", &function); | |
220 | if (ret < 0) | |
221 | function = NULL; | |
222 | ||
223 | for (i = 0; i < ARRAY_SIZE(cfg_params); i++) { | |
224 | ret = of_property_read_u32(np, cfg_params[i].property, &val); | |
225 | if (!ret) { | |
226 | config = TEGRA_PINCONF_PACK(cfg_params[i].param, val); | |
227 | ret = add_config(&configs, &num_configs, config); | |
228 | if (ret < 0) | |
229 | goto exit; | |
230 | } | |
231 | } | |
232 | ||
233 | reserve = 0; | |
234 | if (function != NULL) | |
235 | reserve++; | |
236 | if (num_configs) | |
237 | reserve++; | |
238 | ret = of_property_count_strings(np, "nvidia,pins"); | |
239 | if (ret < 0) | |
240 | goto exit; | |
241 | reserve *= ret; | |
242 | ||
243 | ret = reserve_map(map, reserved_maps, num_maps, reserve); | |
244 | if (ret < 0) | |
245 | goto exit; | |
246 | ||
247 | of_property_for_each_string(np, "nvidia,pins", prop, group) { | |
248 | if (function) { | |
249 | ret = add_map_mux(map, reserved_maps, num_maps, | |
250 | group, function); | |
251 | if (ret < 0) | |
252 | goto exit; | |
253 | } | |
254 | ||
255 | if (num_configs) { | |
256 | ret = add_map_configs(map, reserved_maps, num_maps, | |
257 | group, configs, num_configs); | |
258 | if (ret < 0) | |
259 | goto exit; | |
260 | } | |
261 | } | |
262 | ||
263 | ret = 0; | |
264 | ||
265 | exit: | |
266 | kfree(configs); | |
267 | return ret; | |
268 | } | |
269 | ||
270 | int tegra_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev, | |
271 | struct device_node *np_config, | |
272 | struct pinctrl_map **map, unsigned *num_maps) | |
273 | { | |
274 | unsigned reserved_maps; | |
275 | struct device_node *np; | |
276 | int ret; | |
277 | ||
278 | reserved_maps = 0; | |
279 | *map = NULL; | |
280 | *num_maps = 0; | |
281 | ||
282 | for_each_child_of_node(np_config, np) { | |
283 | ret = tegra_pinctrl_dt_subnode_to_map(np, map, &reserved_maps, | |
284 | num_maps); | |
285 | if (ret < 0) { | |
286 | tegra_pinctrl_dt_free_map(pctldev, *map, *num_maps); | |
287 | return ret; | |
288 | } | |
289 | } | |
290 | ||
291 | return 0; | |
292 | } | |
293 | ||
971dac71 | 294 | static struct pinctrl_ops tegra_pinctrl_ops = { |
d1e90e9e | 295 | .get_groups_count = tegra_pinctrl_get_groups_count, |
971dac71 SW |
296 | .get_group_name = tegra_pinctrl_get_group_name, |
297 | .get_group_pins = tegra_pinctrl_get_group_pins, | |
298 | .pin_dbg_show = tegra_pinctrl_pin_dbg_show, | |
60f7f500 SW |
299 | .dt_node_to_map = tegra_pinctrl_dt_node_to_map, |
300 | .dt_free_map = tegra_pinctrl_dt_free_map, | |
971dac71 SW |
301 | }; |
302 | ||
d1e90e9e | 303 | static int tegra_pinctrl_get_funcs_count(struct pinctrl_dev *pctldev) |
971dac71 SW |
304 | { |
305 | struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); | |
306 | ||
d1e90e9e | 307 | return pmx->soc->nfunctions; |
971dac71 SW |
308 | } |
309 | ||
310 | static const char *tegra_pinctrl_get_func_name(struct pinctrl_dev *pctldev, | |
311 | unsigned function) | |
312 | { | |
313 | struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); | |
314 | ||
971dac71 SW |
315 | return pmx->soc->functions[function].name; |
316 | } | |
317 | ||
318 | static int tegra_pinctrl_get_func_groups(struct pinctrl_dev *pctldev, | |
319 | unsigned function, | |
320 | const char * const **groups, | |
321 | unsigned * const num_groups) | |
322 | { | |
323 | struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); | |
324 | ||
971dac71 SW |
325 | *groups = pmx->soc->functions[function].groups; |
326 | *num_groups = pmx->soc->functions[function].ngroups; | |
327 | ||
328 | return 0; | |
329 | } | |
330 | ||
331 | static int tegra_pinctrl_enable(struct pinctrl_dev *pctldev, unsigned function, | |
332 | unsigned group) | |
333 | { | |
334 | struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); | |
335 | const struct tegra_pingroup *g; | |
336 | int i; | |
337 | u32 val; | |
338 | ||
971dac71 SW |
339 | g = &pmx->soc->groups[group]; |
340 | ||
341 | if (g->mux_reg < 0) | |
342 | return -EINVAL; | |
343 | ||
344 | for (i = 0; i < ARRAY_SIZE(g->funcs); i++) { | |
345 | if (g->funcs[i] == function) | |
346 | break; | |
347 | } | |
348 | if (i == ARRAY_SIZE(g->funcs)) | |
349 | return -EINVAL; | |
350 | ||
351 | val = pmx_readl(pmx, g->mux_bank, g->mux_reg); | |
352 | val &= ~(0x3 << g->mux_bit); | |
353 | val |= i << g->mux_bit; | |
354 | pmx_writel(pmx, val, g->mux_bank, g->mux_reg); | |
355 | ||
356 | return 0; | |
357 | } | |
358 | ||
359 | static void tegra_pinctrl_disable(struct pinctrl_dev *pctldev, | |
360 | unsigned function, unsigned group) | |
361 | { | |
362 | struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); | |
363 | const struct tegra_pingroup *g; | |
364 | u32 val; | |
365 | ||
971dac71 SW |
366 | g = &pmx->soc->groups[group]; |
367 | ||
368 | if (g->mux_reg < 0) | |
369 | return; | |
370 | ||
371 | val = pmx_readl(pmx, g->mux_bank, g->mux_reg); | |
372 | val &= ~(0x3 << g->mux_bit); | |
373 | val |= g->func_safe << g->mux_bit; | |
374 | pmx_writel(pmx, val, g->mux_bank, g->mux_reg); | |
375 | } | |
376 | ||
377 | static struct pinmux_ops tegra_pinmux_ops = { | |
d1e90e9e | 378 | .get_functions_count = tegra_pinctrl_get_funcs_count, |
971dac71 SW |
379 | .get_function_name = tegra_pinctrl_get_func_name, |
380 | .get_function_groups = tegra_pinctrl_get_func_groups, | |
381 | .enable = tegra_pinctrl_enable, | |
382 | .disable = tegra_pinctrl_disable, | |
383 | }; | |
384 | ||
385 | static int tegra_pinconf_reg(struct tegra_pmx *pmx, | |
386 | const struct tegra_pingroup *g, | |
387 | enum tegra_pinconf_param param, | |
388 | s8 *bank, s16 *reg, s8 *bit, s8 *width) | |
389 | { | |
390 | switch (param) { | |
391 | case TEGRA_PINCONF_PARAM_PULL: | |
392 | *bank = g->pupd_bank; | |
393 | *reg = g->pupd_reg; | |
394 | *bit = g->pupd_bit; | |
395 | *width = 2; | |
396 | break; | |
397 | case TEGRA_PINCONF_PARAM_TRISTATE: | |
398 | *bank = g->tri_bank; | |
399 | *reg = g->tri_reg; | |
400 | *bit = g->tri_bit; | |
401 | *width = 1; | |
402 | break; | |
403 | case TEGRA_PINCONF_PARAM_ENABLE_INPUT: | |
404 | *bank = g->einput_bank; | |
405 | *reg = g->einput_reg; | |
406 | *bit = g->einput_bit; | |
407 | *width = 1; | |
408 | break; | |
409 | case TEGRA_PINCONF_PARAM_OPEN_DRAIN: | |
410 | *bank = g->odrain_bank; | |
411 | *reg = g->odrain_reg; | |
412 | *bit = g->odrain_bit; | |
413 | *width = 1; | |
414 | break; | |
415 | case TEGRA_PINCONF_PARAM_LOCK: | |
416 | *bank = g->lock_bank; | |
417 | *reg = g->lock_reg; | |
418 | *bit = g->lock_bit; | |
419 | *width = 1; | |
420 | break; | |
421 | case TEGRA_PINCONF_PARAM_IORESET: | |
422 | *bank = g->ioreset_bank; | |
423 | *reg = g->ioreset_reg; | |
424 | *bit = g->ioreset_bit; | |
425 | *width = 1; | |
426 | break; | |
427 | case TEGRA_PINCONF_PARAM_HIGH_SPEED_MODE: | |
428 | *bank = g->drv_bank; | |
429 | *reg = g->drv_reg; | |
430 | *bit = g->hsm_bit; | |
431 | *width = 1; | |
432 | break; | |
433 | case TEGRA_PINCONF_PARAM_SCHMITT: | |
434 | *bank = g->drv_bank; | |
435 | *reg = g->drv_reg; | |
436 | *bit = g->schmitt_bit; | |
437 | *width = 1; | |
438 | break; | |
439 | case TEGRA_PINCONF_PARAM_LOW_POWER_MODE: | |
440 | *bank = g->drv_bank; | |
441 | *reg = g->drv_reg; | |
442 | *bit = g->lpmd_bit; | |
443 | *width = 1; | |
444 | break; | |
445 | case TEGRA_PINCONF_PARAM_DRIVE_DOWN_STRENGTH: | |
446 | *bank = g->drv_bank; | |
447 | *reg = g->drv_reg; | |
448 | *bit = g->drvdn_bit; | |
449 | *width = g->drvdn_width; | |
450 | break; | |
451 | case TEGRA_PINCONF_PARAM_DRIVE_UP_STRENGTH: | |
452 | *bank = g->drv_bank; | |
453 | *reg = g->drv_reg; | |
454 | *bit = g->drvup_bit; | |
455 | *width = g->drvup_width; | |
456 | break; | |
457 | case TEGRA_PINCONF_PARAM_SLEW_RATE_FALLING: | |
458 | *bank = g->drv_bank; | |
459 | *reg = g->drv_reg; | |
460 | *bit = g->slwf_bit; | |
461 | *width = g->slwf_width; | |
462 | break; | |
463 | case TEGRA_PINCONF_PARAM_SLEW_RATE_RISING: | |
464 | *bank = g->drv_bank; | |
465 | *reg = g->drv_reg; | |
466 | *bit = g->slwr_bit; | |
467 | *width = g->slwr_width; | |
468 | break; | |
469 | default: | |
470 | dev_err(pmx->dev, "Invalid config param %04x\n", param); | |
471 | return -ENOTSUPP; | |
472 | } | |
473 | ||
474 | if (*reg < 0) { | |
475 | dev_err(pmx->dev, | |
476 | "Config param %04x not supported on group %s\n", | |
477 | param, g->name); | |
478 | return -ENOTSUPP; | |
479 | } | |
480 | ||
481 | return 0; | |
482 | } | |
483 | ||
484 | static int tegra_pinconf_get(struct pinctrl_dev *pctldev, | |
485 | unsigned pin, unsigned long *config) | |
486 | { | |
487 | return -ENOTSUPP; | |
488 | } | |
489 | ||
490 | static int tegra_pinconf_set(struct pinctrl_dev *pctldev, | |
491 | unsigned pin, unsigned long config) | |
492 | { | |
493 | return -ENOTSUPP; | |
494 | } | |
495 | ||
496 | static int tegra_pinconf_group_get(struct pinctrl_dev *pctldev, | |
497 | unsigned group, unsigned long *config) | |
498 | { | |
499 | struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); | |
500 | enum tegra_pinconf_param param = TEGRA_PINCONF_UNPACK_PARAM(*config); | |
501 | u16 arg; | |
502 | const struct tegra_pingroup *g; | |
503 | int ret; | |
504 | s8 bank, bit, width; | |
505 | s16 reg; | |
506 | u32 val, mask; | |
507 | ||
971dac71 SW |
508 | g = &pmx->soc->groups[group]; |
509 | ||
510 | ret = tegra_pinconf_reg(pmx, g, param, &bank, ®, &bit, &width); | |
511 | if (ret < 0) | |
512 | return ret; | |
513 | ||
514 | val = pmx_readl(pmx, bank, reg); | |
515 | mask = (1 << width) - 1; | |
516 | arg = (val >> bit) & mask; | |
517 | ||
518 | *config = TEGRA_PINCONF_PACK(param, arg); | |
519 | ||
520 | return 0; | |
521 | } | |
522 | ||
523 | static int tegra_pinconf_group_set(struct pinctrl_dev *pctldev, | |
524 | unsigned group, unsigned long config) | |
525 | { | |
526 | struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); | |
527 | enum tegra_pinconf_param param = TEGRA_PINCONF_UNPACK_PARAM(config); | |
528 | u16 arg = TEGRA_PINCONF_UNPACK_ARG(config); | |
529 | const struct tegra_pingroup *g; | |
530 | int ret; | |
531 | s8 bank, bit, width; | |
532 | s16 reg; | |
533 | u32 val, mask; | |
534 | ||
971dac71 SW |
535 | g = &pmx->soc->groups[group]; |
536 | ||
537 | ret = tegra_pinconf_reg(pmx, g, param, &bank, ®, &bit, &width); | |
538 | if (ret < 0) | |
539 | return ret; | |
540 | ||
541 | val = pmx_readl(pmx, bank, reg); | |
542 | ||
543 | /* LOCK can't be cleared */ | |
544 | if (param == TEGRA_PINCONF_PARAM_LOCK) { | |
545 | if ((val & BIT(bit)) && !arg) | |
546 | return -EINVAL; | |
547 | } | |
548 | ||
549 | /* Special-case Boolean values; allow any non-zero as true */ | |
550 | if (width == 1) | |
551 | arg = !!arg; | |
552 | ||
553 | /* Range-check user-supplied value */ | |
554 | mask = (1 << width) - 1; | |
555 | if (arg & ~mask) | |
556 | return -EINVAL; | |
557 | ||
558 | /* Update register */ | |
559 | val &= ~(mask << bit); | |
560 | val |= arg << bit; | |
561 | pmx_writel(pmx, val, bank, reg); | |
562 | ||
563 | return 0; | |
564 | } | |
565 | ||
566 | static void tegra_pinconf_dbg_show(struct pinctrl_dev *pctldev, | |
567 | struct seq_file *s, unsigned offset) | |
568 | { | |
569 | } | |
570 | ||
571 | static void tegra_pinconf_group_dbg_show(struct pinctrl_dev *pctldev, | |
572 | struct seq_file *s, unsigned selector) | |
573 | { | |
574 | } | |
575 | ||
576 | struct pinconf_ops tegra_pinconf_ops = { | |
577 | .pin_config_get = tegra_pinconf_get, | |
578 | .pin_config_set = tegra_pinconf_set, | |
579 | .pin_config_group_get = tegra_pinconf_group_get, | |
580 | .pin_config_group_set = tegra_pinconf_group_set, | |
581 | .pin_config_dbg_show = tegra_pinconf_dbg_show, | |
582 | .pin_config_group_dbg_show = tegra_pinconf_group_dbg_show, | |
583 | }; | |
584 | ||
585 | static struct pinctrl_gpio_range tegra_pinctrl_gpio_range = { | |
586 | .name = "Tegra GPIOs", | |
587 | .id = 0, | |
588 | .base = 0, | |
589 | }; | |
590 | ||
591 | static struct pinctrl_desc tegra_pinctrl_desc = { | |
592 | .name = DRIVER_NAME, | |
593 | .pctlops = &tegra_pinctrl_ops, | |
594 | .pmxops = &tegra_pinmux_ops, | |
595 | .confops = &tegra_pinconf_ops, | |
596 | .owner = THIS_MODULE, | |
597 | }; | |
598 | ||
599 | static struct of_device_id tegra_pinctrl_of_match[] __devinitdata = { | |
600 | #ifdef CONFIG_PINCTRL_TEGRA20 | |
601 | { | |
602 | .compatible = "nvidia,tegra20-pinmux-disabled", | |
603 | .data = tegra20_pinctrl_init, | |
604 | }, | |
605 | #endif | |
606 | #ifdef CONFIG_PINCTRL_TEGRA30 | |
607 | { | |
608 | .compatible = "nvidia,tegra30-pinmux-disabled", | |
609 | .data = tegra30_pinctrl_init, | |
610 | }, | |
611 | #endif | |
612 | {}, | |
613 | }; | |
614 | ||
615 | static int __devinit tegra_pinctrl_probe(struct platform_device *pdev) | |
616 | { | |
617 | const struct of_device_id *match; | |
618 | tegra_pinctrl_soc_initf initf = NULL; | |
619 | struct tegra_pmx *pmx; | |
620 | struct resource *res; | |
621 | int i; | |
622 | ||
623 | match = of_match_device(tegra_pinctrl_of_match, &pdev->dev); | |
624 | if (match) | |
625 | initf = (tegra_pinctrl_soc_initf)match->data; | |
626 | #ifdef CONFIG_PINCTRL_TEGRA20 | |
627 | if (!initf) | |
628 | initf = tegra20_pinctrl_init; | |
629 | #endif | |
630 | if (!initf) { | |
631 | dev_err(&pdev->dev, | |
632 | "Could not determine SoC-specific init func\n"); | |
633 | return -EINVAL; | |
634 | } | |
635 | ||
636 | pmx = devm_kzalloc(&pdev->dev, sizeof(*pmx), GFP_KERNEL); | |
637 | if (!pmx) { | |
638 | dev_err(&pdev->dev, "Can't alloc tegra_pmx\n"); | |
639 | return -ENOMEM; | |
640 | } | |
641 | pmx->dev = &pdev->dev; | |
642 | ||
643 | (*initf)(&pmx->soc); | |
644 | ||
645 | tegra_pinctrl_gpio_range.npins = pmx->soc->ngpios; | |
646 | tegra_pinctrl_desc.pins = pmx->soc->pins; | |
647 | tegra_pinctrl_desc.npins = pmx->soc->npins; | |
648 | ||
649 | for (i = 0; ; i++) { | |
650 | res = platform_get_resource(pdev, IORESOURCE_MEM, i); | |
651 | if (!res) | |
652 | break; | |
653 | } | |
654 | pmx->nbanks = i; | |
655 | ||
656 | pmx->regs = devm_kzalloc(&pdev->dev, pmx->nbanks * sizeof(*pmx->regs), | |
657 | GFP_KERNEL); | |
658 | if (!pmx->regs) { | |
659 | dev_err(&pdev->dev, "Can't alloc regs pointer\n"); | |
660 | return -ENODEV; | |
661 | } | |
662 | ||
663 | for (i = 0; i < pmx->nbanks; i++) { | |
664 | res = platform_get_resource(pdev, IORESOURCE_MEM, i); | |
665 | if (!res) { | |
666 | dev_err(&pdev->dev, "Missing MEM resource\n"); | |
667 | return -ENODEV; | |
668 | } | |
669 | ||
670 | if (!devm_request_mem_region(&pdev->dev, res->start, | |
671 | resource_size(res), | |
672 | dev_name(&pdev->dev))) { | |
673 | dev_err(&pdev->dev, | |
674 | "Couldn't request MEM resource %d\n", i); | |
675 | return -ENODEV; | |
676 | } | |
677 | ||
678 | pmx->regs[i] = devm_ioremap(&pdev->dev, res->start, | |
679 | resource_size(res)); | |
680 | if (!pmx->regs[i]) { | |
681 | dev_err(&pdev->dev, "Couldn't ioremap regs %d\n", i); | |
682 | return -ENODEV; | |
683 | } | |
684 | } | |
685 | ||
686 | pmx->pctl = pinctrl_register(&tegra_pinctrl_desc, &pdev->dev, pmx); | |
687 | if (IS_ERR(pmx->pctl)) { | |
688 | dev_err(&pdev->dev, "Couldn't register pinctrl driver\n"); | |
689 | return PTR_ERR(pmx->pctl); | |
690 | } | |
691 | ||
692 | pinctrl_add_gpio_range(pmx->pctl, &tegra_pinctrl_gpio_range); | |
693 | ||
694 | platform_set_drvdata(pdev, pmx); | |
695 | ||
696 | dev_dbg(&pdev->dev, "Probed Tegra pinctrl driver\n"); | |
697 | ||
698 | return 0; | |
699 | } | |
700 | ||
701 | static int __devexit tegra_pinctrl_remove(struct platform_device *pdev) | |
702 | { | |
703 | struct tegra_pmx *pmx = platform_get_drvdata(pdev); | |
704 | ||
705 | pinctrl_remove_gpio_range(pmx->pctl, &tegra_pinctrl_gpio_range); | |
706 | pinctrl_unregister(pmx->pctl); | |
707 | ||
708 | return 0; | |
709 | } | |
710 | ||
711 | static struct platform_driver tegra_pinctrl_driver = { | |
712 | .driver = { | |
713 | .name = DRIVER_NAME, | |
714 | .owner = THIS_MODULE, | |
715 | .of_match_table = tegra_pinctrl_of_match, | |
716 | }, | |
717 | .probe = tegra_pinctrl_probe, | |
718 | .remove = __devexit_p(tegra_pinctrl_remove), | |
719 | }; | |
720 | ||
721 | static int __init tegra_pinctrl_init(void) | |
722 | { | |
723 | return platform_driver_register(&tegra_pinctrl_driver); | |
724 | } | |
725 | arch_initcall(tegra_pinctrl_init); | |
726 | ||
727 | static void __exit tegra_pinctrl_exit(void) | |
728 | { | |
729 | platform_driver_unregister(&tegra_pinctrl_driver); | |
730 | } | |
731 | module_exit(tegra_pinctrl_exit); | |
732 | ||
733 | MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>"); | |
734 | MODULE_DESCRIPTION("NVIDIA Tegra pinctrl driver"); | |
735 | MODULE_LICENSE("GPL v2"); | |
736 | MODULE_DEVICE_TABLE(of, tegra_pinctrl_of_match); |