aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pinctrl/pinctrl-tegra.c
diff options
context:
space:
mode:
authorStephen Warren <swarren@nvidia.com>2012-02-01 16:04:47 -0500
committerLinus Walleij <linus.walleij@linaro.org>2012-03-06 04:51:46 -0500
commit971dac7123c785fdb0d09276b5d459b67585e242 (patch)
treebf31a25b47b9b7504e6f0765bf1a97b28d8afa44 /drivers/pinctrl/pinctrl-tegra.c
parent62aa2b537c6f5957afd98e29f96897419ed5ebab (diff)
pinctrl: add a driver for NVIDIA Tegra
This adds a driver for the Tegra pinmux, and required parameterization data for Tegra20 and Tegra30. The driver is initially added with driver name and device tree compatible value that won't cause this driver to be used. A later change will switch the pinctrl driver to use the correct values, switch the old pinmux driver to be disabled, and update all code that uses the old pinmux APIs to use the new pinctrl APIs. Signed-off-by: Stephen Warren <swarren@nvidia.com> Acked-by: Olof Johansson <olof@lixom.net> [squashed "fix case of Tegra30's foo_groups[] arrays"] Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Diffstat (limited to 'drivers/pinctrl/pinctrl-tegra.c')
-rw-r--r--drivers/pinctrl/pinctrl-tegra.c559
1 files changed, 559 insertions, 0 deletions
diff --git a/drivers/pinctrl/pinctrl-tegra.c b/drivers/pinctrl/pinctrl-tegra.c
new file mode 100644
index 000000000000..9b329688120c
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-tegra.c
@@ -0,0 +1,559 @@
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>
26#include <linux/pinctrl/pinctrl.h>
27#include <linux/pinctrl/pinmux.h>
28#include <linux/pinctrl/pinconf.h>
29
30#include <mach/pinconf-tegra.h>
31
32#include "pinctrl-tegra.h"
33
34#define DRIVER_NAME "tegra-pinmux-disabled"
35
36struct tegra_pmx {
37 struct device *dev;
38 struct pinctrl_dev *pctl;
39
40 const struct tegra_pinctrl_soc_data *soc;
41
42 int nbanks;
43 void __iomem **regs;
44};
45
46static inline u32 pmx_readl(struct tegra_pmx *pmx, u32 bank, u32 reg)
47{
48 return readl(pmx->regs[bank] + reg);
49}
50
51static inline void pmx_writel(struct tegra_pmx *pmx, u32 val, u32 bank, u32 reg)
52{
53 writel(val, pmx->regs[bank] + reg);
54}
55
56static int tegra_pinctrl_list_groups(struct pinctrl_dev *pctldev,
57 unsigned group)
58{
59 struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
60
61 if (group >= pmx->soc->ngroups)
62 return -EINVAL;
63
64 return 0;
65}
66
67static const char *tegra_pinctrl_get_group_name(struct pinctrl_dev *pctldev,
68 unsigned group)
69{
70 struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
71
72 if (group >= pmx->soc->ngroups)
73 return NULL;
74
75 return pmx->soc->groups[group].name;
76}
77
78static int tegra_pinctrl_get_group_pins(struct pinctrl_dev *pctldev,
79 unsigned group,
80 const unsigned **pins,
81 unsigned *num_pins)
82{
83 struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
84
85 if (group >= pmx->soc->ngroups)
86 return -EINVAL;
87
88 *pins = pmx->soc->groups[group].pins;
89 *num_pins = pmx->soc->groups[group].npins;
90
91 return 0;
92}
93
94static void tegra_pinctrl_pin_dbg_show(struct pinctrl_dev *pctldev,
95 struct seq_file *s,
96 unsigned offset)
97{
98 seq_printf(s, " " DRIVER_NAME);
99}
100
101static struct pinctrl_ops tegra_pinctrl_ops = {
102 .list_groups = tegra_pinctrl_list_groups,
103 .get_group_name = tegra_pinctrl_get_group_name,
104 .get_group_pins = tegra_pinctrl_get_group_pins,
105 .pin_dbg_show = tegra_pinctrl_pin_dbg_show,
106};
107
108static int tegra_pinctrl_list_funcs(struct pinctrl_dev *pctldev,
109 unsigned function)
110{
111 struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
112
113 if (function >= pmx->soc->nfunctions)
114 return -EINVAL;
115
116 return 0;
117}
118
119static const char *tegra_pinctrl_get_func_name(struct pinctrl_dev *pctldev,
120 unsigned function)
121{
122 struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
123
124 if (function >= pmx->soc->nfunctions)
125 return NULL;
126
127 return pmx->soc->functions[function].name;
128}
129
130static int tegra_pinctrl_get_func_groups(struct pinctrl_dev *pctldev,
131 unsigned function,
132 const char * const **groups,
133 unsigned * const num_groups)
134{
135 struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
136
137 if (function >= pmx->soc->nfunctions)
138 return -EINVAL;
139
140 *groups = pmx->soc->functions[function].groups;
141 *num_groups = pmx->soc->functions[function].ngroups;
142
143 return 0;
144}
145
146static int tegra_pinctrl_enable(struct pinctrl_dev *pctldev, unsigned function,
147 unsigned group)
148{
149 struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
150 const struct tegra_pingroup *g;
151 int i;
152 u32 val;
153
154 if (group >= pmx->soc->ngroups)
155 return -EINVAL;
156 g = &pmx->soc->groups[group];
157
158 if (g->mux_reg < 0)
159 return -EINVAL;
160
161 for (i = 0; i < ARRAY_SIZE(g->funcs); i++) {
162 if (g->funcs[i] == function)
163 break;
164 }
165 if (i == ARRAY_SIZE(g->funcs))
166 return -EINVAL;
167
168 val = pmx_readl(pmx, g->mux_bank, g->mux_reg);
169 val &= ~(0x3 << g->mux_bit);
170 val |= i << g->mux_bit;
171 pmx_writel(pmx, val, g->mux_bank, g->mux_reg);
172
173 return 0;
174}
175
176static void tegra_pinctrl_disable(struct pinctrl_dev *pctldev,
177 unsigned function, unsigned group)
178{
179 struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
180 const struct tegra_pingroup *g;
181 u32 val;
182
183 if (group >= pmx->soc->ngroups)
184 return;
185 g = &pmx->soc->groups[group];
186
187 if (g->mux_reg < 0)
188 return;
189
190 val = pmx_readl(pmx, g->mux_bank, g->mux_reg);
191 val &= ~(0x3 << g->mux_bit);
192 val |= g->func_safe << g->mux_bit;
193 pmx_writel(pmx, val, g->mux_bank, g->mux_reg);
194}
195
196static struct pinmux_ops tegra_pinmux_ops = {
197 .list_functions = tegra_pinctrl_list_funcs,
198 .get_function_name = tegra_pinctrl_get_func_name,
199 .get_function_groups = tegra_pinctrl_get_func_groups,
200 .enable = tegra_pinctrl_enable,
201 .disable = tegra_pinctrl_disable,
202};
203
204static int tegra_pinconf_reg(struct tegra_pmx *pmx,
205 const struct tegra_pingroup *g,
206 enum tegra_pinconf_param param,
207 s8 *bank, s16 *reg, s8 *bit, s8 *width)
208{
209 switch (param) {
210 case TEGRA_PINCONF_PARAM_PULL:
211 *bank = g->pupd_bank;
212 *reg = g->pupd_reg;
213 *bit = g->pupd_bit;
214 *width = 2;
215 break;
216 case TEGRA_PINCONF_PARAM_TRISTATE:
217 *bank = g->tri_bank;
218 *reg = g->tri_reg;
219 *bit = g->tri_bit;
220 *width = 1;
221 break;
222 case TEGRA_PINCONF_PARAM_ENABLE_INPUT:
223 *bank = g->einput_bank;
224 *reg = g->einput_reg;
225 *bit = g->einput_bit;
226 *width = 1;
227 break;
228 case TEGRA_PINCONF_PARAM_OPEN_DRAIN:
229 *bank = g->odrain_bank;
230 *reg = g->odrain_reg;
231 *bit = g->odrain_bit;
232 *width = 1;
233 break;
234 case TEGRA_PINCONF_PARAM_LOCK:
235 *bank = g->lock_bank;
236 *reg = g->lock_reg;
237 *bit = g->lock_bit;
238 *width = 1;
239 break;
240 case TEGRA_PINCONF_PARAM_IORESET:
241 *bank = g->ioreset_bank;
242 *reg = g->ioreset_reg;
243 *bit = g->ioreset_bit;
244 *width = 1;
245 break;
246 case TEGRA_PINCONF_PARAM_HIGH_SPEED_MODE:
247 *bank = g->drv_bank;
248 *reg = g->drv_reg;
249 *bit = g->hsm_bit;
250 *width = 1;
251 break;
252 case TEGRA_PINCONF_PARAM_SCHMITT:
253 *bank = g->drv_bank;
254 *reg = g->drv_reg;
255 *bit = g->schmitt_bit;
256 *width = 1;
257 break;
258 case TEGRA_PINCONF_PARAM_LOW_POWER_MODE:
259 *bank = g->drv_bank;
260 *reg = g->drv_reg;
261 *bit = g->lpmd_bit;
262 *width = 1;
263 break;
264 case TEGRA_PINCONF_PARAM_DRIVE_DOWN_STRENGTH:
265 *bank = g->drv_bank;
266 *reg = g->drv_reg;
267 *bit = g->drvdn_bit;
268 *width = g->drvdn_width;
269 break;
270 case TEGRA_PINCONF_PARAM_DRIVE_UP_STRENGTH:
271 *bank = g->drv_bank;
272 *reg = g->drv_reg;
273 *bit = g->drvup_bit;
274 *width = g->drvup_width;
275 break;
276 case TEGRA_PINCONF_PARAM_SLEW_RATE_FALLING:
277 *bank = g->drv_bank;
278 *reg = g->drv_reg;
279 *bit = g->slwf_bit;
280 *width = g->slwf_width;
281 break;
282 case TEGRA_PINCONF_PARAM_SLEW_RATE_RISING:
283 *bank = g->drv_bank;
284 *reg = g->drv_reg;
285 *bit = g->slwr_bit;
286 *width = g->slwr_width;
287 break;
288 default:
289 dev_err(pmx->dev, "Invalid config param %04x\n", param);
290 return -ENOTSUPP;
291 }
292
293 if (*reg < 0) {
294 dev_err(pmx->dev,
295 "Config param %04x not supported on group %s\n",
296 param, g->name);
297 return -ENOTSUPP;
298 }
299
300 return 0;
301}
302
303static int tegra_pinconf_get(struct pinctrl_dev *pctldev,
304 unsigned pin, unsigned long *config)
305{
306 return -ENOTSUPP;
307}
308
309static int tegra_pinconf_set(struct pinctrl_dev *pctldev,
310 unsigned pin, unsigned long config)
311{
312 return -ENOTSUPP;
313}
314
315static int tegra_pinconf_group_get(struct pinctrl_dev *pctldev,
316 unsigned group, unsigned long *config)
317{
318 struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
319 enum tegra_pinconf_param param = TEGRA_PINCONF_UNPACK_PARAM(*config);
320 u16 arg;
321 const struct tegra_pingroup *g;
322 int ret;
323 s8 bank, bit, width;
324 s16 reg;
325 u32 val, mask;
326
327 if (group >= pmx->soc->ngroups)
328 return -EINVAL;
329 g = &pmx->soc->groups[group];
330
331 ret = tegra_pinconf_reg(pmx, g, param, &bank, &reg, &bit, &width);
332 if (ret < 0)
333 return ret;
334
335 val = pmx_readl(pmx, bank, reg);
336 mask = (1 << width) - 1;
337 arg = (val >> bit) & mask;
338
339 *config = TEGRA_PINCONF_PACK(param, arg);
340
341 return 0;
342}
343
344static int tegra_pinconf_group_set(struct pinctrl_dev *pctldev,
345 unsigned group, unsigned long config)
346{
347 struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
348 enum tegra_pinconf_param param = TEGRA_PINCONF_UNPACK_PARAM(config);
349 u16 arg = TEGRA_PINCONF_UNPACK_ARG(config);
350 const struct tegra_pingroup *g;
351 int ret;
352 s8 bank, bit, width;
353 s16 reg;
354 u32 val, mask;
355
356 if (group >= pmx->soc->ngroups)
357 return -EINVAL;
358 g = &pmx->soc->groups[group];
359
360 ret = tegra_pinconf_reg(pmx, g, param, &bank, &reg, &bit, &width);
361 if (ret < 0)
362 return ret;
363
364 val = pmx_readl(pmx, bank, reg);
365
366 /* LOCK can't be cleared */
367 if (param == TEGRA_PINCONF_PARAM_LOCK) {
368 if ((val & BIT(bit)) && !arg)
369 return -EINVAL;
370 }
371
372 /* Special-case Boolean values; allow any non-zero as true */
373 if (width == 1)
374 arg = !!arg;
375
376 /* Range-check user-supplied value */
377 mask = (1 << width) - 1;
378 if (arg & ~mask)
379 return -EINVAL;
380
381 /* Update register */
382 val &= ~(mask << bit);
383 val |= arg << bit;
384 pmx_writel(pmx, val, bank, reg);
385
386 return 0;
387}
388
389static void tegra_pinconf_dbg_show(struct pinctrl_dev *pctldev,
390 struct seq_file *s, unsigned offset)
391{
392}
393
394static void tegra_pinconf_group_dbg_show(struct pinctrl_dev *pctldev,
395 struct seq_file *s, unsigned selector)
396{
397}
398
399struct pinconf_ops tegra_pinconf_ops = {
400 .pin_config_get = tegra_pinconf_get,
401 .pin_config_set = tegra_pinconf_set,
402 .pin_config_group_get = tegra_pinconf_group_get,
403 .pin_config_group_set = tegra_pinconf_group_set,
404 .pin_config_dbg_show = tegra_pinconf_dbg_show,
405 .pin_config_group_dbg_show = tegra_pinconf_group_dbg_show,
406};
407
408static struct pinctrl_gpio_range tegra_pinctrl_gpio_range = {
409 .name = "Tegra GPIOs",
410 .id = 0,
411 .base = 0,
412};
413
414static struct pinctrl_desc tegra_pinctrl_desc = {
415 .name = DRIVER_NAME,
416 .pctlops = &tegra_pinctrl_ops,
417 .pmxops = &tegra_pinmux_ops,
418 .confops = &tegra_pinconf_ops,
419 .owner = THIS_MODULE,
420};
421
422static struct of_device_id tegra_pinctrl_of_match[] __devinitdata = {
423#ifdef CONFIG_PINCTRL_TEGRA20
424 {
425 .compatible = "nvidia,tegra20-pinmux-disabled",
426 .data = tegra20_pinctrl_init,
427 },
428#endif
429#ifdef CONFIG_PINCTRL_TEGRA30
430 {
431 .compatible = "nvidia,tegra30-pinmux-disabled",
432 .data = tegra30_pinctrl_init,
433 },
434#endif
435 {},
436};
437
438static int __devinit tegra_pinctrl_probe(struct platform_device *pdev)
439{
440 const struct of_device_id *match;
441 tegra_pinctrl_soc_initf initf = NULL;
442 struct tegra_pmx *pmx;
443 struct resource *res;
444 int i;
445
446 match = of_match_device(tegra_pinctrl_of_match, &pdev->dev);
447 if (match)
448 initf = (tegra_pinctrl_soc_initf)match->data;
449#ifdef CONFIG_PINCTRL_TEGRA20
450 if (!initf)
451 initf = tegra20_pinctrl_init;
452#endif
453 if (!initf) {
454 dev_err(&pdev->dev,
455 "Could not determine SoC-specific init func\n");
456 return -EINVAL;
457 }
458
459 pmx = devm_kzalloc(&pdev->dev, sizeof(*pmx), GFP_KERNEL);
460 if (!pmx) {
461 dev_err(&pdev->dev, "Can't alloc tegra_pmx\n");
462 return -ENOMEM;
463 }
464 pmx->dev = &pdev->dev;
465
466 (*initf)(&pmx->soc);
467
468 tegra_pinctrl_gpio_range.npins = pmx->soc->ngpios;
469 tegra_pinctrl_desc.pins = pmx->soc->pins;
470 tegra_pinctrl_desc.npins = pmx->soc->npins;
471
472 for (i = 0; ; i++) {
473 res = platform_get_resource(pdev, IORESOURCE_MEM, i);
474 if (!res)
475 break;
476 }
477 pmx->nbanks = i;
478
479 pmx->regs = devm_kzalloc(&pdev->dev, pmx->nbanks * sizeof(*pmx->regs),
480 GFP_KERNEL);
481 if (!pmx->regs) {
482 dev_err(&pdev->dev, "Can't alloc regs pointer\n");
483 return -ENODEV;
484 }
485
486 for (i = 0; i < pmx->nbanks; i++) {
487 res = platform_get_resource(pdev, IORESOURCE_MEM, i);
488 if (!res) {
489 dev_err(&pdev->dev, "Missing MEM resource\n");
490 return -ENODEV;
491 }
492
493 if (!devm_request_mem_region(&pdev->dev, res->start,
494 resource_size(res),
495 dev_name(&pdev->dev))) {
496 dev_err(&pdev->dev,
497 "Couldn't request MEM resource %d\n", i);
498 return -ENODEV;
499 }
500
501 pmx->regs[i] = devm_ioremap(&pdev->dev, res->start,
502 resource_size(res));
503 if (!pmx->regs[i]) {
504 dev_err(&pdev->dev, "Couldn't ioremap regs %d\n", i);
505 return -ENODEV;
506 }
507 }
508
509 pmx->pctl = pinctrl_register(&tegra_pinctrl_desc, &pdev->dev, pmx);
510 if (IS_ERR(pmx->pctl)) {
511 dev_err(&pdev->dev, "Couldn't register pinctrl driver\n");
512 return PTR_ERR(pmx->pctl);
513 }
514
515 pinctrl_add_gpio_range(pmx->pctl, &tegra_pinctrl_gpio_range);
516
517 platform_set_drvdata(pdev, pmx);
518
519 dev_dbg(&pdev->dev, "Probed Tegra pinctrl driver\n");
520
521 return 0;
522}
523
524static int __devexit tegra_pinctrl_remove(struct platform_device *pdev)
525{
526 struct tegra_pmx *pmx = platform_get_drvdata(pdev);
527
528 pinctrl_remove_gpio_range(pmx->pctl, &tegra_pinctrl_gpio_range);
529 pinctrl_unregister(pmx->pctl);
530
531 return 0;
532}
533
534static struct platform_driver tegra_pinctrl_driver = {
535 .driver = {
536 .name = DRIVER_NAME,
537 .owner = THIS_MODULE,
538 .of_match_table = tegra_pinctrl_of_match,
539 },
540 .probe = tegra_pinctrl_probe,
541 .remove = __devexit_p(tegra_pinctrl_remove),
542};
543
544static int __init tegra_pinctrl_init(void)
545{
546 return platform_driver_register(&tegra_pinctrl_driver);
547}
548arch_initcall(tegra_pinctrl_init);
549
550static void __exit tegra_pinctrl_exit(void)
551{
552 platform_driver_unregister(&tegra_pinctrl_driver);
553}
554module_exit(tegra_pinctrl_exit);
555
556MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
557MODULE_DESCRIPTION("NVIDIA Tegra pinctrl driver");
558MODULE_LICENSE("GPL v2");
559MODULE_DEVICE_TABLE(of, tegra_pinctrl_of_match);