blob: 1d201650d7a43c591273c0e9cbb86ffcf75ba899 [file] [log] [blame]
Erik Gillinga4417c82010-02-23 18:46:37 -08001/*
2 * linux/arch/arm/mach-tegra/pinmux.c
3 *
4 * Copyright (C) 2010 Google, Inc.
5 *
6 * This software is licensed under the terms of the GNU General Public
7 * License version 2, as published by the Free Software Foundation, and
8 * may be copied, distributed, and modified under those terms.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 */
16
Colin Crossc5f04b82010-07-09 15:13:52 -070017#include <linux/init.h>
18#include <linux/module.h>
Erik Gillinga4417c82010-02-23 18:46:37 -080019#include <linux/kernel.h>
20#include <linux/errno.h>
21#include <linux/spinlock.h>
22#include <linux/io.h>
Stephen Warren1ebc8492011-10-11 16:16:15 -060023#include <linux/platform_device.h>
Erik Gillinga4417c82010-02-23 18:46:37 -080024
25#include <mach/iomap.h>
26#include <mach/pinmux.h>
27
Erik Gillinga4417c82010-02-23 18:46:37 -080028#define HSM_EN(reg) (((reg) >> 2) & 0x1)
29#define SCHMT_EN(reg) (((reg) >> 3) & 0x1)
30#define LPMD(reg) (((reg) >> 4) & 0x3)
31#define DRVDN(reg) (((reg) >> 12) & 0x1f)
32#define DRVUP(reg) (((reg) >> 20) & 0x1f)
33#define SLWR(reg) (((reg) >> 28) & 0x3)
34#define SLWF(reg) (((reg) >> 30) & 0x3)
35
Colin Crossc5f04b82010-07-09 15:13:52 -070036static const struct tegra_pingroup_desc *const pingroups = tegra_soc_pingroups;
37static const struct tegra_drive_pingroup_desc *const drive_pingroups = tegra_soc_drive_pingroups;
Erik Gillinga4417c82010-02-23 18:46:37 -080038
39static char *tegra_mux_names[TEGRA_MAX_MUX] = {
40 [TEGRA_MUX_AHB_CLK] = "AHB_CLK",
41 [TEGRA_MUX_APB_CLK] = "APB_CLK",
42 [TEGRA_MUX_AUDIO_SYNC] = "AUDIO_SYNC",
43 [TEGRA_MUX_CRT] = "CRT",
44 [TEGRA_MUX_DAP1] = "DAP1",
45 [TEGRA_MUX_DAP2] = "DAP2",
46 [TEGRA_MUX_DAP3] = "DAP3",
47 [TEGRA_MUX_DAP4] = "DAP4",
48 [TEGRA_MUX_DAP5] = "DAP5",
49 [TEGRA_MUX_DISPLAYA] = "DISPLAYA",
50 [TEGRA_MUX_DISPLAYB] = "DISPLAYB",
51 [TEGRA_MUX_EMC_TEST0_DLL] = "EMC_TEST0_DLL",
52 [TEGRA_MUX_EMC_TEST1_DLL] = "EMC_TEST1_DLL",
53 [TEGRA_MUX_GMI] = "GMI",
54 [TEGRA_MUX_GMI_INT] = "GMI_INT",
55 [TEGRA_MUX_HDMI] = "HDMI",
56 [TEGRA_MUX_I2C] = "I2C",
57 [TEGRA_MUX_I2C2] = "I2C2",
58 [TEGRA_MUX_I2C3] = "I2C3",
59 [TEGRA_MUX_IDE] = "IDE",
60 [TEGRA_MUX_IRDA] = "IRDA",
61 [TEGRA_MUX_KBC] = "KBC",
62 [TEGRA_MUX_MIO] = "MIO",
63 [TEGRA_MUX_MIPI_HS] = "MIPI_HS",
64 [TEGRA_MUX_NAND] = "NAND",
65 [TEGRA_MUX_OSC] = "OSC",
66 [TEGRA_MUX_OWR] = "OWR",
67 [TEGRA_MUX_PCIE] = "PCIE",
68 [TEGRA_MUX_PLLA_OUT] = "PLLA_OUT",
69 [TEGRA_MUX_PLLC_OUT1] = "PLLC_OUT1",
70 [TEGRA_MUX_PLLM_OUT1] = "PLLM_OUT1",
71 [TEGRA_MUX_PLLP_OUT2] = "PLLP_OUT2",
72 [TEGRA_MUX_PLLP_OUT3] = "PLLP_OUT3",
73 [TEGRA_MUX_PLLP_OUT4] = "PLLP_OUT4",
74 [TEGRA_MUX_PWM] = "PWM",
75 [TEGRA_MUX_PWR_INTR] = "PWR_INTR",
76 [TEGRA_MUX_PWR_ON] = "PWR_ON",
77 [TEGRA_MUX_RTCK] = "RTCK",
78 [TEGRA_MUX_SDIO1] = "SDIO1",
79 [TEGRA_MUX_SDIO2] = "SDIO2",
80 [TEGRA_MUX_SDIO3] = "SDIO3",
81 [TEGRA_MUX_SDIO4] = "SDIO4",
82 [TEGRA_MUX_SFLASH] = "SFLASH",
83 [TEGRA_MUX_SPDIF] = "SPDIF",
84 [TEGRA_MUX_SPI1] = "SPI1",
85 [TEGRA_MUX_SPI2] = "SPI2",
86 [TEGRA_MUX_SPI2_ALT] = "SPI2_ALT",
87 [TEGRA_MUX_SPI3] = "SPI3",
88 [TEGRA_MUX_SPI4] = "SPI4",
89 [TEGRA_MUX_TRACE] = "TRACE",
90 [TEGRA_MUX_TWC] = "TWC",
91 [TEGRA_MUX_UARTA] = "UARTA",
92 [TEGRA_MUX_UARTB] = "UARTB",
93 [TEGRA_MUX_UARTC] = "UARTC",
94 [TEGRA_MUX_UARTD] = "UARTD",
95 [TEGRA_MUX_UARTE] = "UARTE",
96 [TEGRA_MUX_ULPI] = "ULPI",
97 [TEGRA_MUX_VI] = "VI",
98 [TEGRA_MUX_VI_SENSOR_CLK] = "VI_SENSOR_CLK",
99 [TEGRA_MUX_XIO] = "XIO",
Colin Crossc5f04b82010-07-09 15:13:52 -0700100 [TEGRA_MUX_SAFE] = "<safe>",
Erik Gillinga4417c82010-02-23 18:46:37 -0800101};
102
103static const char *tegra_drive_names[TEGRA_MAX_DRIVE] = {
104 [TEGRA_DRIVE_DIV_8] = "DIV_8",
105 [TEGRA_DRIVE_DIV_4] = "DIV_4",
106 [TEGRA_DRIVE_DIV_2] = "DIV_2",
107 [TEGRA_DRIVE_DIV_1] = "DIV_1",
108};
109
110static const char *tegra_slew_names[TEGRA_MAX_SLEW] = {
111 [TEGRA_SLEW_FASTEST] = "FASTEST",
112 [TEGRA_SLEW_FAST] = "FAST",
113 [TEGRA_SLEW_SLOW] = "SLOW",
114 [TEGRA_SLEW_SLOWEST] = "SLOWEST",
115};
116
117static DEFINE_SPINLOCK(mux_lock);
118
119static const char *pingroup_name(enum tegra_pingroup pg)
120{
121 if (pg < 0 || pg >= TEGRA_MAX_PINGROUP)
122 return "<UNKNOWN>";
123
124 return pingroups[pg].name;
125}
126
127static const char *func_name(enum tegra_mux_func func)
128{
129 if (func == TEGRA_MUX_RSVD1)
130 return "RSVD1";
131
132 if (func == TEGRA_MUX_RSVD2)
133 return "RSVD2";
134
135 if (func == TEGRA_MUX_RSVD3)
136 return "RSVD3";
137
138 if (func == TEGRA_MUX_RSVD4)
139 return "RSVD4";
140
141 if (func == TEGRA_MUX_NONE)
142 return "NONE";
143
144 if (func < 0 || func >= TEGRA_MAX_MUX)
145 return "<UNKNOWN>";
146
147 return tegra_mux_names[func];
148}
149
150
151static const char *tri_name(unsigned long val)
152{
153 return val ? "TRISTATE" : "NORMAL";
154}
155
156static const char *pupd_name(unsigned long val)
157{
158 switch (val) {
159 case 0:
160 return "NORMAL";
161
162 case 1:
163 return "PULL_DOWN";
164
165 case 2:
166 return "PULL_UP";
167
168 default:
169 return "RSVD";
170 }
171}
172
Stephen Warren48f2ece2011-10-12 09:54:27 -0600173static int nbanks;
174static void __iomem **regs;
Erik Gillinga4417c82010-02-23 18:46:37 -0800175
Stephen Warren48f2ece2011-10-12 09:54:27 -0600176static inline u32 pg_readl(u32 bank, u32 reg)
Erik Gillinga4417c82010-02-23 18:46:37 -0800177{
Stephen Warren48f2ece2011-10-12 09:54:27 -0600178 return readl(regs[bank] + reg);
Erik Gillinga4417c82010-02-23 18:46:37 -0800179}
180
Stephen Warren48f2ece2011-10-12 09:54:27 -0600181static inline void pg_writel(u32 val, u32 bank, u32 reg)
Erik Gillinga4417c82010-02-23 18:46:37 -0800182{
Stephen Warren48f2ece2011-10-12 09:54:27 -0600183 writel(val, regs[bank] + reg);
Erik Gillinga4417c82010-02-23 18:46:37 -0800184}
185
Colin Crossc5f04b82010-07-09 15:13:52 -0700186static int tegra_pinmux_set_func(const struct tegra_pingroup_config *config)
Erik Gillinga4417c82010-02-23 18:46:37 -0800187{
188 int mux = -1;
189 int i;
190 unsigned long reg;
191 unsigned long flags;
Colin Crossc5f04b82010-07-09 15:13:52 -0700192 enum tegra_pingroup pg = config->pingroup;
193 enum tegra_mux_func func = config->func;
Erik Gillinga4417c82010-02-23 18:46:37 -0800194
195 if (pg < 0 || pg >= TEGRA_MAX_PINGROUP)
196 return -ERANGE;
197
Colin Crossc5f04b82010-07-09 15:13:52 -0700198 if (pingroups[pg].mux_reg < 0)
Erik Gillinga4417c82010-02-23 18:46:37 -0800199 return -EINVAL;
200
201 if (func < 0)
202 return -ERANGE;
203
Colin Crossc5f04b82010-07-09 15:13:52 -0700204 if (func == TEGRA_MUX_SAFE)
205 func = pingroups[pg].func_safe;
206
Erik Gillinga4417c82010-02-23 18:46:37 -0800207 if (func & TEGRA_MUX_RSVD) {
208 mux = func & 0x3;
209 } else {
210 for (i = 0; i < 4; i++) {
211 if (pingroups[pg].funcs[i] == func) {
212 mux = i;
213 break;
214 }
215 }
216 }
217
218 if (mux < 0)
219 return -EINVAL;
220
221 spin_lock_irqsave(&mux_lock, flags);
222
Stephen Warren48f2ece2011-10-12 09:54:27 -0600223 reg = pg_readl(pingroups[pg].mux_bank, pingroups[pg].mux_reg);
Erik Gillinga4417c82010-02-23 18:46:37 -0800224 reg &= ~(0x3 << pingroups[pg].mux_bit);
225 reg |= mux << pingroups[pg].mux_bit;
Stephen Warren48f2ece2011-10-12 09:54:27 -0600226 pg_writel(reg, pingroups[pg].mux_bank, pingroups[pg].mux_reg);
Erik Gillinga4417c82010-02-23 18:46:37 -0800227
228 spin_unlock_irqrestore(&mux_lock, flags);
229
230 return 0;
231}
232
233int tegra_pinmux_set_tristate(enum tegra_pingroup pg,
234 enum tegra_tristate tristate)
235{
236 unsigned long reg;
237 unsigned long flags;
238
239 if (pg < 0 || pg >= TEGRA_MAX_PINGROUP)
240 return -ERANGE;
241
Colin Crossc5f04b82010-07-09 15:13:52 -0700242 if (pingroups[pg].tri_reg < 0)
Erik Gillinga4417c82010-02-23 18:46:37 -0800243 return -EINVAL;
244
245 spin_lock_irqsave(&mux_lock, flags);
246
Stephen Warren48f2ece2011-10-12 09:54:27 -0600247 reg = pg_readl(pingroups[pg].tri_bank, pingroups[pg].tri_reg);
Erik Gillinga4417c82010-02-23 18:46:37 -0800248 reg &= ~(0x1 << pingroups[pg].tri_bit);
249 if (tristate)
250 reg |= 1 << pingroups[pg].tri_bit;
Stephen Warren48f2ece2011-10-12 09:54:27 -0600251 pg_writel(reg, pingroups[pg].tri_bank, pingroups[pg].tri_reg);
Erik Gillinga4417c82010-02-23 18:46:37 -0800252
253 spin_unlock_irqrestore(&mux_lock, flags);
254
255 return 0;
256}
257
258int tegra_pinmux_set_pullupdown(enum tegra_pingroup pg,
259 enum tegra_pullupdown pupd)
260{
261 unsigned long reg;
262 unsigned long flags;
263
264 if (pg < 0 || pg >= TEGRA_MAX_PINGROUP)
265 return -ERANGE;
266
Colin Crossc5f04b82010-07-09 15:13:52 -0700267 if (pingroups[pg].pupd_reg < 0)
Erik Gillinga4417c82010-02-23 18:46:37 -0800268 return -EINVAL;
269
270 if (pupd != TEGRA_PUPD_NORMAL &&
271 pupd != TEGRA_PUPD_PULL_DOWN &&
272 pupd != TEGRA_PUPD_PULL_UP)
273 return -EINVAL;
274
275
276 spin_lock_irqsave(&mux_lock, flags);
277
Stephen Warren48f2ece2011-10-12 09:54:27 -0600278 reg = pg_readl(pingroups[pg].pupd_bank, pingroups[pg].pupd_reg);
Erik Gillinga4417c82010-02-23 18:46:37 -0800279 reg &= ~(0x3 << pingroups[pg].pupd_bit);
280 reg |= pupd << pingroups[pg].pupd_bit;
Stephen Warren48f2ece2011-10-12 09:54:27 -0600281 pg_writel(reg, pingroups[pg].pupd_bank, pingroups[pg].pupd_reg);
Erik Gillinga4417c82010-02-23 18:46:37 -0800282
283 spin_unlock_irqrestore(&mux_lock, flags);
284
285 return 0;
286}
287
Colin Crossc5f04b82010-07-09 15:13:52 -0700288static void tegra_pinmux_config_pingroup(const struct tegra_pingroup_config *config)
Erik Gillinga4417c82010-02-23 18:46:37 -0800289{
Colin Crossc5f04b82010-07-09 15:13:52 -0700290 enum tegra_pingroup pingroup = config->pingroup;
291 enum tegra_mux_func func = config->func;
292 enum tegra_pullupdown pupd = config->pupd;
293 enum tegra_tristate tristate = config->tristate;
Erik Gillinga4417c82010-02-23 18:46:37 -0800294 int err;
295
Colin Crossc5f04b82010-07-09 15:13:52 -0700296 if (pingroups[pingroup].mux_reg >= 0) {
297 err = tegra_pinmux_set_func(config);
Erik Gillinga4417c82010-02-23 18:46:37 -0800298 if (err < 0)
299 pr_err("pinmux: can't set pingroup %s func to %s: %d\n",
300 pingroup_name(pingroup), func_name(func), err);
301 }
302
Colin Crossc5f04b82010-07-09 15:13:52 -0700303 if (pingroups[pingroup].pupd_reg >= 0) {
Erik Gillinga4417c82010-02-23 18:46:37 -0800304 err = tegra_pinmux_set_pullupdown(pingroup, pupd);
305 if (err < 0)
306 pr_err("pinmux: can't set pingroup %s pullupdown to %s: %d\n",
307 pingroup_name(pingroup), pupd_name(pupd), err);
308 }
309
Colin Crossc5f04b82010-07-09 15:13:52 -0700310 if (pingroups[pingroup].tri_reg >= 0) {
Erik Gillinga4417c82010-02-23 18:46:37 -0800311 err = tegra_pinmux_set_tristate(pingroup, tristate);
312 if (err < 0)
313 pr_err("pinmux: can't set pingroup %s tristate to %s: %d\n",
314 pingroup_name(pingroup), tri_name(func), err);
315 }
316}
317
Colin Crossc5f04b82010-07-09 15:13:52 -0700318void tegra_pinmux_config_table(const struct tegra_pingroup_config *config, int len)
Erik Gillinga4417c82010-02-23 18:46:37 -0800319{
320 int i;
321
322 for (i = 0; i < len; i++)
Colin Crossc5f04b82010-07-09 15:13:52 -0700323 tegra_pinmux_config_pingroup(&config[i]);
Erik Gillinga4417c82010-02-23 18:46:37 -0800324}
325
326static const char *drive_pinmux_name(enum tegra_drive_pingroup pg)
327{
328 if (pg < 0 || pg >= TEGRA_MAX_DRIVE_PINGROUP)
329 return "<UNKNOWN>";
330
331 return drive_pingroups[pg].name;
332}
333
334static const char *enable_name(unsigned long val)
335{
336 return val ? "ENABLE" : "DISABLE";
337}
338
339static const char *drive_name(unsigned long val)
340{
341 if (val >= TEGRA_MAX_DRIVE)
342 return "<UNKNOWN>";
343
344 return tegra_drive_names[val];
345}
346
347static const char *slew_name(unsigned long val)
348{
349 if (val >= TEGRA_MAX_SLEW)
350 return "<UNKNOWN>";
351
352 return tegra_slew_names[val];
353}
354
355static int tegra_drive_pinmux_set_hsm(enum tegra_drive_pingroup pg,
356 enum tegra_hsm hsm)
357{
358 unsigned long flags;
359 u32 reg;
360 if (pg < 0 || pg >= TEGRA_MAX_DRIVE_PINGROUP)
361 return -ERANGE;
362
363 if (hsm != TEGRA_HSM_ENABLE && hsm != TEGRA_HSM_DISABLE)
364 return -EINVAL;
365
366 spin_lock_irqsave(&mux_lock, flags);
367
Stephen Warren48f2ece2011-10-12 09:54:27 -0600368 reg = pg_readl(drive_pingroups[pg].reg_bank, drive_pingroups[pg].reg);
Erik Gillinga4417c82010-02-23 18:46:37 -0800369 if (hsm == TEGRA_HSM_ENABLE)
370 reg |= (1 << 2);
371 else
372 reg &= ~(1 << 2);
Stephen Warren48f2ece2011-10-12 09:54:27 -0600373 pg_writel(reg, drive_pingroups[pg].reg_bank, drive_pingroups[pg].reg);
Erik Gillinga4417c82010-02-23 18:46:37 -0800374
375 spin_unlock_irqrestore(&mux_lock, flags);
376
377 return 0;
378}
379
380static int tegra_drive_pinmux_set_schmitt(enum tegra_drive_pingroup pg,
381 enum tegra_schmitt schmitt)
382{
383 unsigned long flags;
384 u32 reg;
385 if (pg < 0 || pg >= TEGRA_MAX_DRIVE_PINGROUP)
386 return -ERANGE;
387
388 if (schmitt != TEGRA_SCHMITT_ENABLE && schmitt != TEGRA_SCHMITT_DISABLE)
389 return -EINVAL;
390
391 spin_lock_irqsave(&mux_lock, flags);
392
Stephen Warren48f2ece2011-10-12 09:54:27 -0600393 reg = pg_readl(drive_pingroups[pg].reg_bank, drive_pingroups[pg].reg);
Erik Gillinga4417c82010-02-23 18:46:37 -0800394 if (schmitt == TEGRA_SCHMITT_ENABLE)
395 reg |= (1 << 3);
396 else
397 reg &= ~(1 << 3);
Stephen Warren48f2ece2011-10-12 09:54:27 -0600398 pg_writel(reg, drive_pingroups[pg].reg_bank, drive_pingroups[pg].reg);
Erik Gillinga4417c82010-02-23 18:46:37 -0800399
400 spin_unlock_irqrestore(&mux_lock, flags);
401
402 return 0;
403}
404
405static int tegra_drive_pinmux_set_drive(enum tegra_drive_pingroup pg,
406 enum tegra_drive drive)
407{
408 unsigned long flags;
409 u32 reg;
410 if (pg < 0 || pg >= TEGRA_MAX_DRIVE_PINGROUP)
411 return -ERANGE;
412
413 if (drive < 0 || drive >= TEGRA_MAX_DRIVE)
414 return -EINVAL;
415
416 spin_lock_irqsave(&mux_lock, flags);
417
Stephen Warren48f2ece2011-10-12 09:54:27 -0600418 reg = pg_readl(drive_pingroups[pg].reg_bank, drive_pingroups[pg].reg);
Erik Gillinga4417c82010-02-23 18:46:37 -0800419 reg &= ~(0x3 << 4);
420 reg |= drive << 4;
Stephen Warren48f2ece2011-10-12 09:54:27 -0600421 pg_writel(reg, drive_pingroups[pg].reg_bank, drive_pingroups[pg].reg);
Erik Gillinga4417c82010-02-23 18:46:37 -0800422
423 spin_unlock_irqrestore(&mux_lock, flags);
424
425 return 0;
426}
427
428static int tegra_drive_pinmux_set_pull_down(enum tegra_drive_pingroup pg,
429 enum tegra_pull_strength pull_down)
430{
431 unsigned long flags;
432 u32 reg;
433 if (pg < 0 || pg >= TEGRA_MAX_DRIVE_PINGROUP)
434 return -ERANGE;
435
436 if (pull_down < 0 || pull_down >= TEGRA_MAX_PULL)
437 return -EINVAL;
438
439 spin_lock_irqsave(&mux_lock, flags);
440
Stephen Warren48f2ece2011-10-12 09:54:27 -0600441 reg = pg_readl(drive_pingroups[pg].reg_bank, drive_pingroups[pg].reg);
Erik Gillinga4417c82010-02-23 18:46:37 -0800442 reg &= ~(0x1f << 12);
443 reg |= pull_down << 12;
Stephen Warren48f2ece2011-10-12 09:54:27 -0600444 pg_writel(reg, drive_pingroups[pg].reg_bank, drive_pingroups[pg].reg);
Erik Gillinga4417c82010-02-23 18:46:37 -0800445
446 spin_unlock_irqrestore(&mux_lock, flags);
447
448 return 0;
449}
450
451static int tegra_drive_pinmux_set_pull_up(enum tegra_drive_pingroup pg,
452 enum tegra_pull_strength pull_up)
453{
454 unsigned long flags;
455 u32 reg;
456 if (pg < 0 || pg >= TEGRA_MAX_DRIVE_PINGROUP)
457 return -ERANGE;
458
459 if (pull_up < 0 || pull_up >= TEGRA_MAX_PULL)
460 return -EINVAL;
461
462 spin_lock_irqsave(&mux_lock, flags);
463
Stephen Warren48f2ece2011-10-12 09:54:27 -0600464 reg = pg_readl(drive_pingroups[pg].reg_bank, drive_pingroups[pg].reg);
Erik Gillinga4417c82010-02-23 18:46:37 -0800465 reg &= ~(0x1f << 12);
466 reg |= pull_up << 12;
Stephen Warren48f2ece2011-10-12 09:54:27 -0600467 pg_writel(reg, drive_pingroups[pg].reg_bank, drive_pingroups[pg].reg);
Erik Gillinga4417c82010-02-23 18:46:37 -0800468
469 spin_unlock_irqrestore(&mux_lock, flags);
470
471 return 0;
472}
473
474static int tegra_drive_pinmux_set_slew_rising(enum tegra_drive_pingroup pg,
475 enum tegra_slew slew_rising)
476{
477 unsigned long flags;
478 u32 reg;
479 if (pg < 0 || pg >= TEGRA_MAX_DRIVE_PINGROUP)
480 return -ERANGE;
481
482 if (slew_rising < 0 || slew_rising >= TEGRA_MAX_SLEW)
483 return -EINVAL;
484
485 spin_lock_irqsave(&mux_lock, flags);
486
Stephen Warren48f2ece2011-10-12 09:54:27 -0600487 reg = pg_readl(drive_pingroups[pg].reg_bank, drive_pingroups[pg].reg);
Erik Gillinga4417c82010-02-23 18:46:37 -0800488 reg &= ~(0x3 << 28);
489 reg |= slew_rising << 28;
Stephen Warren48f2ece2011-10-12 09:54:27 -0600490 pg_writel(reg, drive_pingroups[pg].reg_bank, drive_pingroups[pg].reg);
Erik Gillinga4417c82010-02-23 18:46:37 -0800491
492 spin_unlock_irqrestore(&mux_lock, flags);
493
494 return 0;
495}
496
497static int tegra_drive_pinmux_set_slew_falling(enum tegra_drive_pingroup pg,
498 enum tegra_slew slew_falling)
499{
500 unsigned long flags;
501 u32 reg;
502 if (pg < 0 || pg >= TEGRA_MAX_DRIVE_PINGROUP)
503 return -ERANGE;
504
505 if (slew_falling < 0 || slew_falling >= TEGRA_MAX_SLEW)
506 return -EINVAL;
507
508 spin_lock_irqsave(&mux_lock, flags);
509
Stephen Warren48f2ece2011-10-12 09:54:27 -0600510 reg = pg_readl(drive_pingroups[pg].reg_bank, drive_pingroups[pg].reg);
Erik Gillinga4417c82010-02-23 18:46:37 -0800511 reg &= ~(0x3 << 30);
512 reg |= slew_falling << 30;
Stephen Warren48f2ece2011-10-12 09:54:27 -0600513 pg_writel(reg, drive_pingroups[pg].reg_bank, drive_pingroups[pg].reg);
Erik Gillinga4417c82010-02-23 18:46:37 -0800514
515 spin_unlock_irqrestore(&mux_lock, flags);
516
517 return 0;
518}
519
520static void tegra_drive_pinmux_config_pingroup(enum tegra_drive_pingroup pingroup,
521 enum tegra_hsm hsm,
522 enum tegra_schmitt schmitt,
523 enum tegra_drive drive,
524 enum tegra_pull_strength pull_down,
525 enum tegra_pull_strength pull_up,
526 enum tegra_slew slew_rising,
527 enum tegra_slew slew_falling)
528{
529 int err;
530
531 err = tegra_drive_pinmux_set_hsm(pingroup, hsm);
532 if (err < 0)
533 pr_err("pinmux: can't set pingroup %s hsm to %s: %d\n",
534 drive_pinmux_name(pingroup),
535 enable_name(hsm), err);
536
537 err = tegra_drive_pinmux_set_schmitt(pingroup, schmitt);
538 if (err < 0)
539 pr_err("pinmux: can't set pingroup %s schmitt to %s: %d\n",
540 drive_pinmux_name(pingroup),
541 enable_name(schmitt), err);
542
543 err = tegra_drive_pinmux_set_drive(pingroup, drive);
544 if (err < 0)
545 pr_err("pinmux: can't set pingroup %s drive to %s: %d\n",
546 drive_pinmux_name(pingroup),
547 drive_name(drive), err);
548
549 err = tegra_drive_pinmux_set_pull_down(pingroup, pull_down);
550 if (err < 0)
551 pr_err("pinmux: can't set pingroup %s pull down to %d: %d\n",
552 drive_pinmux_name(pingroup),
553 pull_down, err);
554
555 err = tegra_drive_pinmux_set_pull_up(pingroup, pull_up);
556 if (err < 0)
557 pr_err("pinmux: can't set pingroup %s pull up to %d: %d\n",
558 drive_pinmux_name(pingroup),
559 pull_up, err);
560
561 err = tegra_drive_pinmux_set_slew_rising(pingroup, slew_rising);
562 if (err < 0)
563 pr_err("pinmux: can't set pingroup %s rising slew to %s: %d\n",
564 drive_pinmux_name(pingroup),
565 slew_name(slew_rising), err);
566
567 err = tegra_drive_pinmux_set_slew_falling(pingroup, slew_falling);
568 if (err < 0)
569 pr_err("pinmux: can't set pingroup %s falling slew to %s: %d\n",
570 drive_pinmux_name(pingroup),
571 slew_name(slew_falling), err);
572}
573
574void tegra_drive_pinmux_config_table(struct tegra_drive_pingroup_config *config,
575 int len)
576{
577 int i;
578
579 for (i = 0; i < len; i++)
580 tegra_drive_pinmux_config_pingroup(config[i].pingroup,
581 config[i].hsm,
582 config[i].schmitt,
583 config[i].drive,
584 config[i].pull_down,
585 config[i].pull_up,
586 config[i].slew_rising,
587 config[i].slew_falling);
588}
589
Colin Crossc5f04b82010-07-09 15:13:52 -0700590void tegra_pinmux_set_safe_pinmux_table(const struct tegra_pingroup_config *config,
591 int len)
592{
593 int i;
594 struct tegra_pingroup_config c;
595
596 for (i = 0; i < len; i++) {
597 int err;
598 c = config[i];
599 if (c.pingroup < 0 || c.pingroup >= TEGRA_MAX_PINGROUP) {
600 WARN_ON(1);
601 continue;
602 }
603 c.func = pingroups[c.pingroup].func_safe;
604 err = tegra_pinmux_set_func(&c);
605 if (err < 0)
606 pr_err("%s: tegra_pinmux_set_func returned %d setting "
607 "%s to %s\n", __func__, err,
608 pingroup_name(c.pingroup), func_name(c.func));
609 }
610}
611
612void tegra_pinmux_config_pinmux_table(const struct tegra_pingroup_config *config,
613 int len)
614{
615 int i;
616
617 for (i = 0; i < len; i++) {
618 int err;
619 if (config[i].pingroup < 0 ||
620 config[i].pingroup >= TEGRA_MAX_PINGROUP) {
621 WARN_ON(1);
622 continue;
623 }
624 err = tegra_pinmux_set_func(&config[i]);
625 if (err < 0)
626 pr_err("%s: tegra_pinmux_set_func returned %d setting "
627 "%s to %s\n", __func__, err,
628 pingroup_name(config[i].pingroup),
629 func_name(config[i].func));
630 }
631}
632
633void tegra_pinmux_config_tristate_table(const struct tegra_pingroup_config *config,
634 int len, enum tegra_tristate tristate)
635{
636 int i;
637 int err;
638 enum tegra_pingroup pingroup;
639
640 for (i = 0; i < len; i++) {
641 pingroup = config[i].pingroup;
642 if (pingroups[pingroup].tri_reg >= 0) {
643 err = tegra_pinmux_set_tristate(pingroup, tristate);
644 if (err < 0)
645 pr_err("pinmux: can't set pingroup %s tristate"
646 " to %s: %d\n", pingroup_name(pingroup),
647 tri_name(tristate), err);
648 }
649 }
650}
651
652void tegra_pinmux_config_pullupdown_table(const struct tegra_pingroup_config *config,
653 int len, enum tegra_pullupdown pupd)
654{
655 int i;
656 int err;
657 enum tegra_pingroup pingroup;
658
659 for (i = 0; i < len; i++) {
660 pingroup = config[i].pingroup;
661 if (pingroups[pingroup].pupd_reg >= 0) {
662 err = tegra_pinmux_set_pullupdown(pingroup, pupd);
663 if (err < 0)
664 pr_err("pinmux: can't set pingroup %s pullupdown"
665 " to %s: %d\n", pingroup_name(pingroup),
666 pupd_name(pupd), err);
667 }
668 }
669}
Erik Gillinga4417c82010-02-23 18:46:37 -0800670
Stephen Warren1ebc8492011-10-11 16:16:15 -0600671static int __devinit tegra_pinmux_probe(struct platform_device *pdev)
672{
Stephen Warren48f2ece2011-10-12 09:54:27 -0600673 struct resource *res;
674 int i;
675 int config_bad = 0;
676
677 for (i = 0; ; i++) {
678 res = platform_get_resource(pdev, IORESOURCE_MEM, i);
679 if (!res)
680 break;
681 }
682 nbanks = i;
683
684 for (i = 0; i < TEGRA_MAX_PINGROUP; i++) {
685 if (pingroups[i].tri_bank >= nbanks) {
686 dev_err(&pdev->dev, "pingroup %d: bad tri_bank\n", i);
687 config_bad = 1;
688 }
689
690 if (pingroups[i].mux_bank >= nbanks) {
691 dev_err(&pdev->dev, "pingroup %d: bad mux_bank\n", i);
692 config_bad = 1;
693 }
694
695 if (pingroups[i].pupd_bank >= nbanks) {
696 dev_err(&pdev->dev, "pingroup %d: bad pupd_bank\n", i);
697 config_bad = 1;
698 }
699 }
700
701 for (i = 0; i < TEGRA_MAX_DRIVE_PINGROUP; i++) {
702 if (drive_pingroups[i].reg_bank >= nbanks) {
703 dev_err(&pdev->dev,
704 "drive pingroup %d: bad reg_bank\n", i);
705 config_bad = 1;
706 }
707 }
708
709 if (config_bad)
710 return -ENODEV;
711
712 regs = devm_kzalloc(&pdev->dev, nbanks * sizeof(*regs), GFP_KERNEL);
713 if (!regs) {
714 dev_err(&pdev->dev, "Can't alloc regs pointer\n");
715 return -ENODEV;
716 }
717
718 for (i = 0; i < nbanks; i++) {
719 res = platform_get_resource(pdev, IORESOURCE_MEM, i);
720 if (!res) {
721 dev_err(&pdev->dev, "Missing MEM resource\n");
722 return -ENODEV;
723 }
724
725 if (!devm_request_mem_region(&pdev->dev, res->start,
726 resource_size(res),
727 dev_name(&pdev->dev))) {
728 dev_err(&pdev->dev,
729 "Couldn't request MEM resource %d\n", i);
730 return -ENODEV;
731 }
732
733 regs[i] = devm_ioremap(&pdev->dev, res->start,
734 resource_size(res));
735 if (!regs) {
736 dev_err(&pdev->dev, "Couldn't ioremap regs %d\n", i);
737 return -ENODEV;
738 }
739 }
740
Stephen Warren1ebc8492011-10-11 16:16:15 -0600741 return 0;
742}
743
744static struct of_device_id tegra_pinmux_of_match[] __devinitdata = {
745 { .compatible = "nvidia,tegra20-pinmux", },
746 { },
747};
748
749static struct platform_driver tegra_pinmux_driver = {
750 .driver = {
751 .name = "tegra-pinmux",
752 .owner = THIS_MODULE,
753 .of_match_table = tegra_pinmux_of_match,
754 },
755 .probe = tegra_pinmux_probe,
756};
757
758static int __init tegra_pinmux_init(void)
759{
760 return platform_driver_register(&tegra_pinmux_driver);
761}
762postcore_initcall(tegra_pinmux_init);
763
Erik Gillinga4417c82010-02-23 18:46:37 -0800764#ifdef CONFIG_DEBUG_FS
765
766#include <linux/debugfs.h>
767#include <linux/seq_file.h>
768
769static void dbg_pad_field(struct seq_file *s, int len)
770{
771 seq_putc(s, ',');
772
773 while (len-- > -1)
774 seq_putc(s, ' ');
775}
776
777static int dbg_pinmux_show(struct seq_file *s, void *unused)
778{
779 int i;
780 int len;
781
782 for (i = 0; i < TEGRA_MAX_PINGROUP; i++) {
Stephen Warren48f2ece2011-10-12 09:54:27 -0600783 unsigned long reg;
Erik Gillinga4417c82010-02-23 18:46:37 -0800784 unsigned long tri;
785 unsigned long mux;
786 unsigned long pupd;
787
788 seq_printf(s, "\t{TEGRA_PINGROUP_%s", pingroups[i].name);
789 len = strlen(pingroups[i].name);
790 dbg_pad_field(s, 5 - len);
791
Colin Crossc5f04b82010-07-09 15:13:52 -0700792 if (pingroups[i].mux_reg < 0) {
Erik Gillinga4417c82010-02-23 18:46:37 -0800793 seq_printf(s, "TEGRA_MUX_NONE");
794 len = strlen("NONE");
795 } else {
Stephen Warren48f2ece2011-10-12 09:54:27 -0600796 reg = pg_readl(pingroups[i].mux_bank,
797 pingroups[i].mux_reg);
798 mux = (reg >> pingroups[i].mux_bit) & 0x3;
Erik Gillinga4417c82010-02-23 18:46:37 -0800799 if (pingroups[i].funcs[mux] == TEGRA_MUX_RSVD) {
800 seq_printf(s, "TEGRA_MUX_RSVD%1lu", mux+1);
801 len = 5;
802 } else {
803 seq_printf(s, "TEGRA_MUX_%s",
804 tegra_mux_names[pingroups[i].funcs[mux]]);
805 len = strlen(tegra_mux_names[pingroups[i].funcs[mux]]);
806 }
807 }
808 dbg_pad_field(s, 13-len);
809
Colin Crossc5f04b82010-07-09 15:13:52 -0700810 if (pingroups[i].pupd_reg < 0) {
Erik Gillinga4417c82010-02-23 18:46:37 -0800811 seq_printf(s, "TEGRA_PUPD_NORMAL");
812 len = strlen("NORMAL");
813 } else {
Stephen Warren48f2ece2011-10-12 09:54:27 -0600814 reg = pg_readl(pingroups[i].pupd_bank,
815 pingroups[i].pupd_reg);
816 pupd = (reg >> pingroups[i].pupd_bit) & 0x3;
Erik Gillinga4417c82010-02-23 18:46:37 -0800817 seq_printf(s, "TEGRA_PUPD_%s", pupd_name(pupd));
818 len = strlen(pupd_name(pupd));
819 }
820 dbg_pad_field(s, 9 - len);
821
Colin Crossc5f04b82010-07-09 15:13:52 -0700822 if (pingroups[i].tri_reg < 0) {
Erik Gillinga4417c82010-02-23 18:46:37 -0800823 seq_printf(s, "TEGRA_TRI_NORMAL");
824 } else {
Stephen Warren48f2ece2011-10-12 09:54:27 -0600825 reg = pg_readl(pingroups[i].tri_bank,
826 pingroups[i].tri_reg);
827 tri = (reg >> pingroups[i].tri_bit) & 0x1;
Erik Gillinga4417c82010-02-23 18:46:37 -0800828
829 seq_printf(s, "TEGRA_TRI_%s", tri_name(tri));
830 }
831 seq_printf(s, "},\n");
832 }
833 return 0;
834}
835
836static int dbg_pinmux_open(struct inode *inode, struct file *file)
837{
838 return single_open(file, dbg_pinmux_show, &inode->i_private);
839}
840
841static const struct file_operations debug_fops = {
842 .open = dbg_pinmux_open,
843 .read = seq_read,
844 .llseek = seq_lseek,
845 .release = single_release,
846};
847
848static int dbg_drive_pinmux_show(struct seq_file *s, void *unused)
849{
850 int i;
851 int len;
852
853 for (i = 0; i < TEGRA_MAX_DRIVE_PINGROUP; i++) {
854 u32 reg;
855
856 seq_printf(s, "\t{TEGRA_DRIVE_PINGROUP_%s",
857 drive_pingroups[i].name);
858 len = strlen(drive_pingroups[i].name);
859 dbg_pad_field(s, 7 - len);
860
861
Stephen Warren48f2ece2011-10-12 09:54:27 -0600862 reg = pg_readl(drive_pingroups[i].reg_bank,
863 drive_pingroups[i].reg);
Erik Gillinga4417c82010-02-23 18:46:37 -0800864 if (HSM_EN(reg)) {
865 seq_printf(s, "TEGRA_HSM_ENABLE");
866 len = 16;
867 } else {
868 seq_printf(s, "TEGRA_HSM_DISABLE");
869 len = 17;
870 }
871 dbg_pad_field(s, 17 - len);
872
873 if (SCHMT_EN(reg)) {
874 seq_printf(s, "TEGRA_SCHMITT_ENABLE");
875 len = 21;
876 } else {
877 seq_printf(s, "TEGRA_SCHMITT_DISABLE");
878 len = 22;
879 }
880 dbg_pad_field(s, 22 - len);
881
882 seq_printf(s, "TEGRA_DRIVE_%s", drive_name(LPMD(reg)));
883 len = strlen(drive_name(LPMD(reg)));
884 dbg_pad_field(s, 5 - len);
885
886 seq_printf(s, "TEGRA_PULL_%d", DRVDN(reg));
887 len = DRVDN(reg) < 10 ? 1 : 2;
888 dbg_pad_field(s, 2 - len);
889
890 seq_printf(s, "TEGRA_PULL_%d", DRVUP(reg));
891 len = DRVUP(reg) < 10 ? 1 : 2;
892 dbg_pad_field(s, 2 - len);
893
894 seq_printf(s, "TEGRA_SLEW_%s", slew_name(SLWR(reg)));
895 len = strlen(slew_name(SLWR(reg)));
896 dbg_pad_field(s, 7 - len);
897
898 seq_printf(s, "TEGRA_SLEW_%s", slew_name(SLWF(reg)));
899
900 seq_printf(s, "},\n");
901 }
902 return 0;
903}
904
905static int dbg_drive_pinmux_open(struct inode *inode, struct file *file)
906{
907 return single_open(file, dbg_drive_pinmux_show, &inode->i_private);
908}
909
910static const struct file_operations debug_drive_fops = {
911 .open = dbg_drive_pinmux_open,
912 .read = seq_read,
913 .llseek = seq_lseek,
914 .release = single_release,
915};
916
917static int __init tegra_pinmux_debuginit(void)
918{
919 (void) debugfs_create_file("tegra_pinmux", S_IRUGO,
920 NULL, NULL, &debug_fops);
921 (void) debugfs_create_file("tegra_pinmux_drive", S_IRUGO,
922 NULL, NULL, &debug_drive_fops);
923 return 0;
924}
925late_initcall(tegra_pinmux_debuginit);
926#endif