diff options
author | Stephen Warren <swarren@nvidia.com> | 2011-12-15 16:23:34 -0500 |
---|---|---|
committer | Stephen Warren <swarren@nvidia.com> | 2012-04-18 12:26:39 -0400 |
commit | b7449d95b0cbfb06b9ca9de8c322c470fbc2a873 (patch) | |
tree | 9b504551205137e869e035a6ddf8681c741ca6ad /arch/arm/mach-tegra/pinmux.c | |
parent | f30d12b3ffb321c9d29bd1588940704d9bed2643 (diff) |
ARM: tegra: Remove pre-pinctrl pinmux driver
The pinctrl driver is now active and used by all boards. Remove the
old pinmux driver.
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Acked-by: Linus Walleij <linus.walleij@linaro.org>
Acked-by: Olof Johansson <olof@lixom.net>
Diffstat (limited to 'arch/arm/mach-tegra/pinmux.c')
-rw-r--r-- | arch/arm/mach-tegra/pinmux.c | 987 |
1 files changed, 0 insertions, 987 deletions
diff --git a/arch/arm/mach-tegra/pinmux.c b/arch/arm/mach-tegra/pinmux.c deleted file mode 100644 index 7867a12748dd..000000000000 --- a/arch/arm/mach-tegra/pinmux.c +++ /dev/null | |||
@@ -1,987 +0,0 @@ | |||
1 | /* | ||
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 | |||
17 | #include <linux/init.h> | ||
18 | #include <linux/module.h> | ||
19 | #include <linux/kernel.h> | ||
20 | #include <linux/errno.h> | ||
21 | #include <linux/spinlock.h> | ||
22 | #include <linux/io.h> | ||
23 | #include <linux/platform_device.h> | ||
24 | #include <linux/of_device.h> | ||
25 | |||
26 | #include <mach/iomap.h> | ||
27 | #include <mach/pinmux.h> | ||
28 | |||
29 | #define HSM_EN(reg) (((reg) >> 2) & 0x1) | ||
30 | #define SCHMT_EN(reg) (((reg) >> 3) & 0x1) | ||
31 | #define LPMD(reg) (((reg) >> 4) & 0x3) | ||
32 | #define DRVDN(reg) (((reg) >> 12) & 0x1f) | ||
33 | #define DRVUP(reg) (((reg) >> 20) & 0x1f) | ||
34 | #define SLWR(reg) (((reg) >> 28) & 0x3) | ||
35 | #define SLWF(reg) (((reg) >> 30) & 0x3) | ||
36 | |||
37 | static const struct tegra_pingroup_desc *pingroups; | ||
38 | static const struct tegra_drive_pingroup_desc *drive_pingroups; | ||
39 | static int pingroup_max; | ||
40 | static int drive_max; | ||
41 | |||
42 | static char *tegra_mux_names[TEGRA_MAX_MUX] = { | ||
43 | [TEGRA_MUX_AHB_CLK] = "AHB_CLK", | ||
44 | [TEGRA_MUX_APB_CLK] = "APB_CLK", | ||
45 | [TEGRA_MUX_AUDIO_SYNC] = "AUDIO_SYNC", | ||
46 | [TEGRA_MUX_CRT] = "CRT", | ||
47 | [TEGRA_MUX_DAP1] = "DAP1", | ||
48 | [TEGRA_MUX_DAP2] = "DAP2", | ||
49 | [TEGRA_MUX_DAP3] = "DAP3", | ||
50 | [TEGRA_MUX_DAP4] = "DAP4", | ||
51 | [TEGRA_MUX_DAP5] = "DAP5", | ||
52 | [TEGRA_MUX_DISPLAYA] = "DISPLAYA", | ||
53 | [TEGRA_MUX_DISPLAYB] = "DISPLAYB", | ||
54 | [TEGRA_MUX_EMC_TEST0_DLL] = "EMC_TEST0_DLL", | ||
55 | [TEGRA_MUX_EMC_TEST1_DLL] = "EMC_TEST1_DLL", | ||
56 | [TEGRA_MUX_GMI] = "GMI", | ||
57 | [TEGRA_MUX_GMI_INT] = "GMI_INT", | ||
58 | [TEGRA_MUX_HDMI] = "HDMI", | ||
59 | [TEGRA_MUX_I2C] = "I2C", | ||
60 | [TEGRA_MUX_I2C2] = "I2C2", | ||
61 | [TEGRA_MUX_I2C3] = "I2C3", | ||
62 | [TEGRA_MUX_IDE] = "IDE", | ||
63 | [TEGRA_MUX_IRDA] = "IRDA", | ||
64 | [TEGRA_MUX_KBC] = "KBC", | ||
65 | [TEGRA_MUX_MIO] = "MIO", | ||
66 | [TEGRA_MUX_MIPI_HS] = "MIPI_HS", | ||
67 | [TEGRA_MUX_NAND] = "NAND", | ||
68 | [TEGRA_MUX_OSC] = "OSC", | ||
69 | [TEGRA_MUX_OWR] = "OWR", | ||
70 | [TEGRA_MUX_PCIE] = "PCIE", | ||
71 | [TEGRA_MUX_PLLA_OUT] = "PLLA_OUT", | ||
72 | [TEGRA_MUX_PLLC_OUT1] = "PLLC_OUT1", | ||
73 | [TEGRA_MUX_PLLM_OUT1] = "PLLM_OUT1", | ||
74 | [TEGRA_MUX_PLLP_OUT2] = "PLLP_OUT2", | ||
75 | [TEGRA_MUX_PLLP_OUT3] = "PLLP_OUT3", | ||
76 | [TEGRA_MUX_PLLP_OUT4] = "PLLP_OUT4", | ||
77 | [TEGRA_MUX_PWM] = "PWM", | ||
78 | [TEGRA_MUX_PWR_INTR] = "PWR_INTR", | ||
79 | [TEGRA_MUX_PWR_ON] = "PWR_ON", | ||
80 | [TEGRA_MUX_RTCK] = "RTCK", | ||
81 | [TEGRA_MUX_SDIO1] = "SDIO1", | ||
82 | [TEGRA_MUX_SDIO2] = "SDIO2", | ||
83 | [TEGRA_MUX_SDIO3] = "SDIO3", | ||
84 | [TEGRA_MUX_SDIO4] = "SDIO4", | ||
85 | [TEGRA_MUX_SFLASH] = "SFLASH", | ||
86 | [TEGRA_MUX_SPDIF] = "SPDIF", | ||
87 | [TEGRA_MUX_SPI1] = "SPI1", | ||
88 | [TEGRA_MUX_SPI2] = "SPI2", | ||
89 | [TEGRA_MUX_SPI2_ALT] = "SPI2_ALT", | ||
90 | [TEGRA_MUX_SPI3] = "SPI3", | ||
91 | [TEGRA_MUX_SPI4] = "SPI4", | ||
92 | [TEGRA_MUX_TRACE] = "TRACE", | ||
93 | [TEGRA_MUX_TWC] = "TWC", | ||
94 | [TEGRA_MUX_UARTA] = "UARTA", | ||
95 | [TEGRA_MUX_UARTB] = "UARTB", | ||
96 | [TEGRA_MUX_UARTC] = "UARTC", | ||
97 | [TEGRA_MUX_UARTD] = "UARTD", | ||
98 | [TEGRA_MUX_UARTE] = "UARTE", | ||
99 | [TEGRA_MUX_ULPI] = "ULPI", | ||
100 | [TEGRA_MUX_VI] = "VI", | ||
101 | [TEGRA_MUX_VI_SENSOR_CLK] = "VI_SENSOR_CLK", | ||
102 | [TEGRA_MUX_XIO] = "XIO", | ||
103 | [TEGRA_MUX_BLINK] = "BLINK", | ||
104 | [TEGRA_MUX_CEC] = "CEC", | ||
105 | [TEGRA_MUX_CLK12] = "CLK12", | ||
106 | [TEGRA_MUX_DAP] = "DAP", | ||
107 | [TEGRA_MUX_DAPSDMMC2] = "DAPSDMMC2", | ||
108 | [TEGRA_MUX_DDR] = "DDR", | ||
109 | [TEGRA_MUX_DEV3] = "DEV3", | ||
110 | [TEGRA_MUX_DTV] = "DTV", | ||
111 | [TEGRA_MUX_VI_ALT1] = "VI_ALT1", | ||
112 | [TEGRA_MUX_VI_ALT2] = "VI_ALT2", | ||
113 | [TEGRA_MUX_VI_ALT3] = "VI_ALT3", | ||
114 | [TEGRA_MUX_EMC_DLL] = "EMC_DLL", | ||
115 | [TEGRA_MUX_EXTPERIPH1] = "EXTPERIPH1", | ||
116 | [TEGRA_MUX_EXTPERIPH2] = "EXTPERIPH2", | ||
117 | [TEGRA_MUX_EXTPERIPH3] = "EXTPERIPH3", | ||
118 | [TEGRA_MUX_GMI_ALT] = "GMI_ALT", | ||
119 | [TEGRA_MUX_HDA] = "HDA", | ||
120 | [TEGRA_MUX_HSI] = "HSI", | ||
121 | [TEGRA_MUX_I2C4] = "I2C4", | ||
122 | [TEGRA_MUX_I2C5] = "I2C5", | ||
123 | [TEGRA_MUX_I2CPWR] = "I2CPWR", | ||
124 | [TEGRA_MUX_I2S0] = "I2S0", | ||
125 | [TEGRA_MUX_I2S1] = "I2S1", | ||
126 | [TEGRA_MUX_I2S2] = "I2S2", | ||
127 | [TEGRA_MUX_I2S3] = "I2S3", | ||
128 | [TEGRA_MUX_I2S4] = "I2S4", | ||
129 | [TEGRA_MUX_NAND_ALT] = "NAND_ALT", | ||
130 | [TEGRA_MUX_POPSDIO4] = "POPSDIO4", | ||
131 | [TEGRA_MUX_POPSDMMC4] = "POPSDMMC4", | ||
132 | [TEGRA_MUX_PWM0] = "PWM0", | ||
133 | [TEGRA_MUX_PWM1] = "PWM2", | ||
134 | [TEGRA_MUX_PWM2] = "PWM2", | ||
135 | [TEGRA_MUX_PWM3] = "PWM3", | ||
136 | [TEGRA_MUX_SATA] = "SATA", | ||
137 | [TEGRA_MUX_SPI5] = "SPI5", | ||
138 | [TEGRA_MUX_SPI6] = "SPI6", | ||
139 | [TEGRA_MUX_SYSCLK] = "SYSCLK", | ||
140 | [TEGRA_MUX_VGP1] = "VGP1", | ||
141 | [TEGRA_MUX_VGP2] = "VGP2", | ||
142 | [TEGRA_MUX_VGP3] = "VGP3", | ||
143 | [TEGRA_MUX_VGP4] = "VGP4", | ||
144 | [TEGRA_MUX_VGP5] = "VGP5", | ||
145 | [TEGRA_MUX_VGP6] = "VGP6", | ||
146 | [TEGRA_MUX_SAFE] = "<safe>", | ||
147 | }; | ||
148 | |||
149 | static const char *tegra_drive_names[TEGRA_MAX_DRIVE] = { | ||
150 | [TEGRA_DRIVE_DIV_8] = "DIV_8", | ||
151 | [TEGRA_DRIVE_DIV_4] = "DIV_4", | ||
152 | [TEGRA_DRIVE_DIV_2] = "DIV_2", | ||
153 | [TEGRA_DRIVE_DIV_1] = "DIV_1", | ||
154 | }; | ||
155 | |||
156 | static const char *tegra_slew_names[TEGRA_MAX_SLEW] = { | ||
157 | [TEGRA_SLEW_FASTEST] = "FASTEST", | ||
158 | [TEGRA_SLEW_FAST] = "FAST", | ||
159 | [TEGRA_SLEW_SLOW] = "SLOW", | ||
160 | [TEGRA_SLEW_SLOWEST] = "SLOWEST", | ||
161 | }; | ||
162 | |||
163 | static DEFINE_SPINLOCK(mux_lock); | ||
164 | |||
165 | static const char *pingroup_name(int pg) | ||
166 | { | ||
167 | if (pg < 0 || pg >= pingroup_max) | ||
168 | return "<UNKNOWN>"; | ||
169 | |||
170 | return pingroups[pg].name; | ||
171 | } | ||
172 | |||
173 | static const char *func_name(enum tegra_mux_func func) | ||
174 | { | ||
175 | if (func == TEGRA_MUX_RSVD1) | ||
176 | return "RSVD1"; | ||
177 | |||
178 | if (func == TEGRA_MUX_RSVD2) | ||
179 | return "RSVD2"; | ||
180 | |||
181 | if (func == TEGRA_MUX_RSVD3) | ||
182 | return "RSVD3"; | ||
183 | |||
184 | if (func == TEGRA_MUX_RSVD4) | ||
185 | return "RSVD4"; | ||
186 | |||
187 | if (func == TEGRA_MUX_NONE) | ||
188 | return "NONE"; | ||
189 | |||
190 | if (func < 0 || func >= TEGRA_MAX_MUX) | ||
191 | return "<UNKNOWN>"; | ||
192 | |||
193 | return tegra_mux_names[func]; | ||
194 | } | ||
195 | |||
196 | |||
197 | static const char *tri_name(unsigned long val) | ||
198 | { | ||
199 | return val ? "TRISTATE" : "NORMAL"; | ||
200 | } | ||
201 | |||
202 | static const char *pupd_name(unsigned long val) | ||
203 | { | ||
204 | switch (val) { | ||
205 | case 0: | ||
206 | return "NORMAL"; | ||
207 | |||
208 | case 1: | ||
209 | return "PULL_DOWN"; | ||
210 | |||
211 | case 2: | ||
212 | return "PULL_UP"; | ||
213 | |||
214 | default: | ||
215 | return "RSVD"; | ||
216 | } | ||
217 | } | ||
218 | |||
219 | static int nbanks; | ||
220 | static void __iomem **regs; | ||
221 | |||
222 | static inline u32 pg_readl(u32 bank, u32 reg) | ||
223 | { | ||
224 | return readl(regs[bank] + reg); | ||
225 | } | ||
226 | |||
227 | static inline void pg_writel(u32 val, u32 bank, u32 reg) | ||
228 | { | ||
229 | writel(val, regs[bank] + reg); | ||
230 | } | ||
231 | |||
232 | static int tegra_pinmux_set_func(const struct tegra_pingroup_config *config) | ||
233 | { | ||
234 | int mux = -1; | ||
235 | int i; | ||
236 | unsigned long reg; | ||
237 | unsigned long flags; | ||
238 | int pg = config->pingroup; | ||
239 | enum tegra_mux_func func = config->func; | ||
240 | |||
241 | if (pg < 0 || pg >= pingroup_max) | ||
242 | return -ERANGE; | ||
243 | |||
244 | if (pingroups[pg].mux_reg < 0) | ||
245 | return -EINVAL; | ||
246 | |||
247 | if (func < 0) | ||
248 | return -ERANGE; | ||
249 | |||
250 | if (func == TEGRA_MUX_SAFE) | ||
251 | func = pingroups[pg].func_safe; | ||
252 | |||
253 | if (func & TEGRA_MUX_RSVD) { | ||
254 | mux = func & 0x3; | ||
255 | } else { | ||
256 | for (i = 0; i < 4; i++) { | ||
257 | if (pingroups[pg].funcs[i] == func) { | ||
258 | mux = i; | ||
259 | break; | ||
260 | } | ||
261 | } | ||
262 | } | ||
263 | |||
264 | if (mux < 0) | ||
265 | return -EINVAL; | ||
266 | |||
267 | spin_lock_irqsave(&mux_lock, flags); | ||
268 | |||
269 | reg = pg_readl(pingroups[pg].mux_bank, pingroups[pg].mux_reg); | ||
270 | reg &= ~(0x3 << pingroups[pg].mux_bit); | ||
271 | reg |= mux << pingroups[pg].mux_bit; | ||
272 | pg_writel(reg, pingroups[pg].mux_bank, pingroups[pg].mux_reg); | ||
273 | |||
274 | spin_unlock_irqrestore(&mux_lock, flags); | ||
275 | |||
276 | return 0; | ||
277 | } | ||
278 | |||
279 | int tegra_pinmux_set_tristate(int pg, enum tegra_tristate tristate) | ||
280 | { | ||
281 | unsigned long reg; | ||
282 | unsigned long flags; | ||
283 | |||
284 | if (pg < 0 || pg >= pingroup_max) | ||
285 | return -ERANGE; | ||
286 | |||
287 | if (pingroups[pg].tri_reg < 0) | ||
288 | return -EINVAL; | ||
289 | |||
290 | spin_lock_irqsave(&mux_lock, flags); | ||
291 | |||
292 | reg = pg_readl(pingroups[pg].tri_bank, pingroups[pg].tri_reg); | ||
293 | reg &= ~(0x1 << pingroups[pg].tri_bit); | ||
294 | if (tristate) | ||
295 | reg |= 1 << pingroups[pg].tri_bit; | ||
296 | pg_writel(reg, pingroups[pg].tri_bank, pingroups[pg].tri_reg); | ||
297 | |||
298 | spin_unlock_irqrestore(&mux_lock, flags); | ||
299 | |||
300 | return 0; | ||
301 | } | ||
302 | |||
303 | int tegra_pinmux_set_pullupdown(int pg, enum tegra_pullupdown pupd) | ||
304 | { | ||
305 | unsigned long reg; | ||
306 | unsigned long flags; | ||
307 | |||
308 | if (pg < 0 || pg >= pingroup_max) | ||
309 | return -ERANGE; | ||
310 | |||
311 | if (pingroups[pg].pupd_reg < 0) | ||
312 | return -EINVAL; | ||
313 | |||
314 | if (pupd != TEGRA_PUPD_NORMAL && | ||
315 | pupd != TEGRA_PUPD_PULL_DOWN && | ||
316 | pupd != TEGRA_PUPD_PULL_UP) | ||
317 | return -EINVAL; | ||
318 | |||
319 | |||
320 | spin_lock_irqsave(&mux_lock, flags); | ||
321 | |||
322 | reg = pg_readl(pingroups[pg].pupd_bank, pingroups[pg].pupd_reg); | ||
323 | reg &= ~(0x3 << pingroups[pg].pupd_bit); | ||
324 | reg |= pupd << pingroups[pg].pupd_bit; | ||
325 | pg_writel(reg, pingroups[pg].pupd_bank, pingroups[pg].pupd_reg); | ||
326 | |||
327 | spin_unlock_irqrestore(&mux_lock, flags); | ||
328 | |||
329 | return 0; | ||
330 | } | ||
331 | |||
332 | static void tegra_pinmux_config_pingroup(const struct tegra_pingroup_config *config) | ||
333 | { | ||
334 | int pingroup = config->pingroup; | ||
335 | enum tegra_mux_func func = config->func; | ||
336 | enum tegra_pullupdown pupd = config->pupd; | ||
337 | enum tegra_tristate tristate = config->tristate; | ||
338 | int err; | ||
339 | |||
340 | if (pingroups[pingroup].mux_reg >= 0) { | ||
341 | err = tegra_pinmux_set_func(config); | ||
342 | if (err < 0) | ||
343 | pr_err("pinmux: can't set pingroup %s func to %s: %d\n", | ||
344 | pingroup_name(pingroup), func_name(func), err); | ||
345 | } | ||
346 | |||
347 | if (pingroups[pingroup].pupd_reg >= 0) { | ||
348 | err = tegra_pinmux_set_pullupdown(pingroup, pupd); | ||
349 | if (err < 0) | ||
350 | pr_err("pinmux: can't set pingroup %s pullupdown to %s: %d\n", | ||
351 | pingroup_name(pingroup), pupd_name(pupd), err); | ||
352 | } | ||
353 | |||
354 | if (pingroups[pingroup].tri_reg >= 0) { | ||
355 | err = tegra_pinmux_set_tristate(pingroup, tristate); | ||
356 | if (err < 0) | ||
357 | pr_err("pinmux: can't set pingroup %s tristate to %s: %d\n", | ||
358 | pingroup_name(pingroup), tri_name(func), err); | ||
359 | } | ||
360 | } | ||
361 | |||
362 | void tegra_pinmux_config_table(const struct tegra_pingroup_config *config, int len) | ||
363 | { | ||
364 | int i; | ||
365 | |||
366 | for (i = 0; i < len; i++) | ||
367 | tegra_pinmux_config_pingroup(&config[i]); | ||
368 | } | ||
369 | |||
370 | static const char *drive_pinmux_name(int pg) | ||
371 | { | ||
372 | if (pg < 0 || pg >= drive_max) | ||
373 | return "<UNKNOWN>"; | ||
374 | |||
375 | return drive_pingroups[pg].name; | ||
376 | } | ||
377 | |||
378 | static const char *enable_name(unsigned long val) | ||
379 | { | ||
380 | return val ? "ENABLE" : "DISABLE"; | ||
381 | } | ||
382 | |||
383 | static const char *drive_name(unsigned long val) | ||
384 | { | ||
385 | if (val >= TEGRA_MAX_DRIVE) | ||
386 | return "<UNKNOWN>"; | ||
387 | |||
388 | return tegra_drive_names[val]; | ||
389 | } | ||
390 | |||
391 | static const char *slew_name(unsigned long val) | ||
392 | { | ||
393 | if (val >= TEGRA_MAX_SLEW) | ||
394 | return "<UNKNOWN>"; | ||
395 | |||
396 | return tegra_slew_names[val]; | ||
397 | } | ||
398 | |||
399 | static int tegra_drive_pinmux_set_hsm(int pg, enum tegra_hsm hsm) | ||
400 | { | ||
401 | unsigned long flags; | ||
402 | u32 reg; | ||
403 | if (pg < 0 || pg >= drive_max) | ||
404 | return -ERANGE; | ||
405 | |||
406 | if (hsm != TEGRA_HSM_ENABLE && hsm != TEGRA_HSM_DISABLE) | ||
407 | return -EINVAL; | ||
408 | |||
409 | spin_lock_irqsave(&mux_lock, flags); | ||
410 | |||
411 | reg = pg_readl(drive_pingroups[pg].reg_bank, drive_pingroups[pg].reg); | ||
412 | if (hsm == TEGRA_HSM_ENABLE) | ||
413 | reg |= (1 << 2); | ||
414 | else | ||
415 | reg &= ~(1 << 2); | ||
416 | pg_writel(reg, drive_pingroups[pg].reg_bank, drive_pingroups[pg].reg); | ||
417 | |||
418 | spin_unlock_irqrestore(&mux_lock, flags); | ||
419 | |||
420 | return 0; | ||
421 | } | ||
422 | |||
423 | static int tegra_drive_pinmux_set_schmitt(int pg, enum tegra_schmitt schmitt) | ||
424 | { | ||
425 | unsigned long flags; | ||
426 | u32 reg; | ||
427 | if (pg < 0 || pg >= drive_max) | ||
428 | return -ERANGE; | ||
429 | |||
430 | if (schmitt != TEGRA_SCHMITT_ENABLE && schmitt != TEGRA_SCHMITT_DISABLE) | ||
431 | return -EINVAL; | ||
432 | |||
433 | spin_lock_irqsave(&mux_lock, flags); | ||
434 | |||
435 | reg = pg_readl(drive_pingroups[pg].reg_bank, drive_pingroups[pg].reg); | ||
436 | if (schmitt == TEGRA_SCHMITT_ENABLE) | ||
437 | reg |= (1 << 3); | ||
438 | else | ||
439 | reg &= ~(1 << 3); | ||
440 | pg_writel(reg, drive_pingroups[pg].reg_bank, drive_pingroups[pg].reg); | ||
441 | |||
442 | spin_unlock_irqrestore(&mux_lock, flags); | ||
443 | |||
444 | return 0; | ||
445 | } | ||
446 | |||
447 | static int tegra_drive_pinmux_set_drive(int pg, enum tegra_drive drive) | ||
448 | { | ||
449 | unsigned long flags; | ||
450 | u32 reg; | ||
451 | if (pg < 0 || pg >= drive_max) | ||
452 | return -ERANGE; | ||
453 | |||
454 | if (drive < 0 || drive >= TEGRA_MAX_DRIVE) | ||
455 | return -EINVAL; | ||
456 | |||
457 | spin_lock_irqsave(&mux_lock, flags); | ||
458 | |||
459 | reg = pg_readl(drive_pingroups[pg].reg_bank, drive_pingroups[pg].reg); | ||
460 | reg &= ~(0x3 << 4); | ||
461 | reg |= drive << 4; | ||
462 | pg_writel(reg, drive_pingroups[pg].reg_bank, drive_pingroups[pg].reg); | ||
463 | |||
464 | spin_unlock_irqrestore(&mux_lock, flags); | ||
465 | |||
466 | return 0; | ||
467 | } | ||
468 | |||
469 | static int tegra_drive_pinmux_set_pull_down(int pg, | ||
470 | enum tegra_pull_strength pull_down) | ||
471 | { | ||
472 | unsigned long flags; | ||
473 | u32 reg; | ||
474 | if (pg < 0 || pg >= drive_max) | ||
475 | return -ERANGE; | ||
476 | |||
477 | if (pull_down < 0 || pull_down >= TEGRA_MAX_PULL) | ||
478 | return -EINVAL; | ||
479 | |||
480 | spin_lock_irqsave(&mux_lock, flags); | ||
481 | |||
482 | reg = pg_readl(drive_pingroups[pg].reg_bank, drive_pingroups[pg].reg); | ||
483 | reg &= ~(0x1f << 12); | ||
484 | reg |= pull_down << 12; | ||
485 | pg_writel(reg, drive_pingroups[pg].reg_bank, drive_pingroups[pg].reg); | ||
486 | |||
487 | spin_unlock_irqrestore(&mux_lock, flags); | ||
488 | |||
489 | return 0; | ||
490 | } | ||
491 | |||
492 | static int tegra_drive_pinmux_set_pull_up(int pg, | ||
493 | enum tegra_pull_strength pull_up) | ||
494 | { | ||
495 | unsigned long flags; | ||
496 | u32 reg; | ||
497 | if (pg < 0 || pg >= drive_max) | ||
498 | return -ERANGE; | ||
499 | |||
500 | if (pull_up < 0 || pull_up >= TEGRA_MAX_PULL) | ||
501 | return -EINVAL; | ||
502 | |||
503 | spin_lock_irqsave(&mux_lock, flags); | ||
504 | |||
505 | reg = pg_readl(drive_pingroups[pg].reg_bank, drive_pingroups[pg].reg); | ||
506 | reg &= ~(0x1f << 12); | ||
507 | reg |= pull_up << 12; | ||
508 | pg_writel(reg, drive_pingroups[pg].reg_bank, drive_pingroups[pg].reg); | ||
509 | |||
510 | spin_unlock_irqrestore(&mux_lock, flags); | ||
511 | |||
512 | return 0; | ||
513 | } | ||
514 | |||
515 | static int tegra_drive_pinmux_set_slew_rising(int pg, | ||
516 | enum tegra_slew slew_rising) | ||
517 | { | ||
518 | unsigned long flags; | ||
519 | u32 reg; | ||
520 | if (pg < 0 || pg >= drive_max) | ||
521 | return -ERANGE; | ||
522 | |||
523 | if (slew_rising < 0 || slew_rising >= TEGRA_MAX_SLEW) | ||
524 | return -EINVAL; | ||
525 | |||
526 | spin_lock_irqsave(&mux_lock, flags); | ||
527 | |||
528 | reg = pg_readl(drive_pingroups[pg].reg_bank, drive_pingroups[pg].reg); | ||
529 | reg &= ~(0x3 << 28); | ||
530 | reg |= slew_rising << 28; | ||
531 | pg_writel(reg, drive_pingroups[pg].reg_bank, drive_pingroups[pg].reg); | ||
532 | |||
533 | spin_unlock_irqrestore(&mux_lock, flags); | ||
534 | |||
535 | return 0; | ||
536 | } | ||
537 | |||
538 | static int tegra_drive_pinmux_set_slew_falling(int pg, | ||
539 | enum tegra_slew slew_falling) | ||
540 | { | ||
541 | unsigned long flags; | ||
542 | u32 reg; | ||
543 | if (pg < 0 || pg >= drive_max) | ||
544 | return -ERANGE; | ||
545 | |||
546 | if (slew_falling < 0 || slew_falling >= TEGRA_MAX_SLEW) | ||
547 | return -EINVAL; | ||
548 | |||
549 | spin_lock_irqsave(&mux_lock, flags); | ||
550 | |||
551 | reg = pg_readl(drive_pingroups[pg].reg_bank, drive_pingroups[pg].reg); | ||
552 | reg &= ~(0x3 << 30); | ||
553 | reg |= slew_falling << 30; | ||
554 | pg_writel(reg, drive_pingroups[pg].reg_bank, drive_pingroups[pg].reg); | ||
555 | |||
556 | spin_unlock_irqrestore(&mux_lock, flags); | ||
557 | |||
558 | return 0; | ||
559 | } | ||
560 | |||
561 | static void tegra_drive_pinmux_config_pingroup(int pingroup, | ||
562 | enum tegra_hsm hsm, | ||
563 | enum tegra_schmitt schmitt, | ||
564 | enum tegra_drive drive, | ||
565 | enum tegra_pull_strength pull_down, | ||
566 | enum tegra_pull_strength pull_up, | ||
567 | enum tegra_slew slew_rising, | ||
568 | enum tegra_slew slew_falling) | ||
569 | { | ||
570 | int err; | ||
571 | |||
572 | err = tegra_drive_pinmux_set_hsm(pingroup, hsm); | ||
573 | if (err < 0) | ||
574 | pr_err("pinmux: can't set pingroup %s hsm to %s: %d\n", | ||
575 | drive_pinmux_name(pingroup), | ||
576 | enable_name(hsm), err); | ||
577 | |||
578 | err = tegra_drive_pinmux_set_schmitt(pingroup, schmitt); | ||
579 | if (err < 0) | ||
580 | pr_err("pinmux: can't set pingroup %s schmitt to %s: %d\n", | ||
581 | drive_pinmux_name(pingroup), | ||
582 | enable_name(schmitt), err); | ||
583 | |||
584 | err = tegra_drive_pinmux_set_drive(pingroup, drive); | ||
585 | if (err < 0) | ||
586 | pr_err("pinmux: can't set pingroup %s drive to %s: %d\n", | ||
587 | drive_pinmux_name(pingroup), | ||
588 | drive_name(drive), err); | ||
589 | |||
590 | err = tegra_drive_pinmux_set_pull_down(pingroup, pull_down); | ||
591 | if (err < 0) | ||
592 | pr_err("pinmux: can't set pingroup %s pull down to %d: %d\n", | ||
593 | drive_pinmux_name(pingroup), | ||
594 | pull_down, err); | ||
595 | |||
596 | err = tegra_drive_pinmux_set_pull_up(pingroup, pull_up); | ||
597 | if (err < 0) | ||
598 | pr_err("pinmux: can't set pingroup %s pull up to %d: %d\n", | ||
599 | drive_pinmux_name(pingroup), | ||
600 | pull_up, err); | ||
601 | |||
602 | err = tegra_drive_pinmux_set_slew_rising(pingroup, slew_rising); | ||
603 | if (err < 0) | ||
604 | pr_err("pinmux: can't set pingroup %s rising slew to %s: %d\n", | ||
605 | drive_pinmux_name(pingroup), | ||
606 | slew_name(slew_rising), err); | ||
607 | |||
608 | err = tegra_drive_pinmux_set_slew_falling(pingroup, slew_falling); | ||
609 | if (err < 0) | ||
610 | pr_err("pinmux: can't set pingroup %s falling slew to %s: %d\n", | ||
611 | drive_pinmux_name(pingroup), | ||
612 | slew_name(slew_falling), err); | ||
613 | } | ||
614 | |||
615 | void tegra_drive_pinmux_config_table(struct tegra_drive_pingroup_config *config, | ||
616 | int len) | ||
617 | { | ||
618 | int i; | ||
619 | |||
620 | for (i = 0; i < len; i++) | ||
621 | tegra_drive_pinmux_config_pingroup(config[i].pingroup, | ||
622 | config[i].hsm, | ||
623 | config[i].schmitt, | ||
624 | config[i].drive, | ||
625 | config[i].pull_down, | ||
626 | config[i].pull_up, | ||
627 | config[i].slew_rising, | ||
628 | config[i].slew_falling); | ||
629 | } | ||
630 | |||
631 | void tegra_pinmux_set_safe_pinmux_table(const struct tegra_pingroup_config *config, | ||
632 | int len) | ||
633 | { | ||
634 | int i; | ||
635 | struct tegra_pingroup_config c; | ||
636 | |||
637 | for (i = 0; i < len; i++) { | ||
638 | int err; | ||
639 | c = config[i]; | ||
640 | if (c.pingroup < 0 || c.pingroup >= pingroup_max) { | ||
641 | WARN_ON(1); | ||
642 | continue; | ||
643 | } | ||
644 | c.func = pingroups[c.pingroup].func_safe; | ||
645 | err = tegra_pinmux_set_func(&c); | ||
646 | if (err < 0) | ||
647 | pr_err("%s: tegra_pinmux_set_func returned %d setting " | ||
648 | "%s to %s\n", __func__, err, | ||
649 | pingroup_name(c.pingroup), func_name(c.func)); | ||
650 | } | ||
651 | } | ||
652 | |||
653 | void tegra_pinmux_config_pinmux_table(const struct tegra_pingroup_config *config, | ||
654 | int len) | ||
655 | { | ||
656 | int i; | ||
657 | |||
658 | for (i = 0; i < len; i++) { | ||
659 | int err; | ||
660 | if (config[i].pingroup < 0 || | ||
661 | config[i].pingroup >= pingroup_max) { | ||
662 | WARN_ON(1); | ||
663 | continue; | ||
664 | } | ||
665 | err = tegra_pinmux_set_func(&config[i]); | ||
666 | if (err < 0) | ||
667 | pr_err("%s: tegra_pinmux_set_func returned %d setting " | ||
668 | "%s to %s\n", __func__, err, | ||
669 | pingroup_name(config[i].pingroup), | ||
670 | func_name(config[i].func)); | ||
671 | } | ||
672 | } | ||
673 | |||
674 | void tegra_pinmux_config_tristate_table(const struct tegra_pingroup_config *config, | ||
675 | int len, enum tegra_tristate tristate) | ||
676 | { | ||
677 | int i; | ||
678 | int err; | ||
679 | int pingroup; | ||
680 | |||
681 | for (i = 0; i < len; i++) { | ||
682 | pingroup = config[i].pingroup; | ||
683 | if (pingroups[pingroup].tri_reg >= 0) { | ||
684 | err = tegra_pinmux_set_tristate(pingroup, tristate); | ||
685 | if (err < 0) | ||
686 | pr_err("pinmux: can't set pingroup %s tristate" | ||
687 | " to %s: %d\n", pingroup_name(pingroup), | ||
688 | tri_name(tristate), err); | ||
689 | } | ||
690 | } | ||
691 | } | ||
692 | |||
693 | void tegra_pinmux_config_pullupdown_table(const struct tegra_pingroup_config *config, | ||
694 | int len, enum tegra_pullupdown pupd) | ||
695 | { | ||
696 | int i; | ||
697 | int err; | ||
698 | int pingroup; | ||
699 | |||
700 | for (i = 0; i < len; i++) { | ||
701 | pingroup = config[i].pingroup; | ||
702 | if (pingroups[pingroup].pupd_reg >= 0) { | ||
703 | err = tegra_pinmux_set_pullupdown(pingroup, pupd); | ||
704 | if (err < 0) | ||
705 | pr_err("pinmux: can't set pingroup %s pullupdown" | ||
706 | " to %s: %d\n", pingroup_name(pingroup), | ||
707 | pupd_name(pupd), err); | ||
708 | } | ||
709 | } | ||
710 | } | ||
711 | |||
712 | static struct of_device_id tegra_pinmux_of_match[] __devinitdata = { | ||
713 | #ifdef CONFIG_ARCH_TEGRA_2x_SOC | ||
714 | { .compatible = "nvidia,tegra20-pinmux-disabled", tegra20_pinmux_init }, | ||
715 | #endif | ||
716 | #ifdef CONFIG_ARCH_TEGRA_3x_SOC | ||
717 | { .compatible = "nvidia,tegra30-pinmux-disabled", tegra30_pinmux_init }, | ||
718 | #endif | ||
719 | { }, | ||
720 | }; | ||
721 | |||
722 | static int __devinit tegra_pinmux_probe(struct platform_device *pdev) | ||
723 | { | ||
724 | struct resource *res; | ||
725 | int i; | ||
726 | int config_bad = 0; | ||
727 | const struct of_device_id *match; | ||
728 | |||
729 | match = of_match_device(tegra_pinmux_of_match, &pdev->dev); | ||
730 | |||
731 | if (match) | ||
732 | ((pinmux_init)(match->data))(&pingroups, &pingroup_max, | ||
733 | &drive_pingroups, &drive_max); | ||
734 | #ifdef CONFIG_ARCH_TEGRA_2x_SOC | ||
735 | else | ||
736 | /* no device tree available, so we must be on tegra20 */ | ||
737 | tegra20_pinmux_init(&pingroups, &pingroup_max, | ||
738 | &drive_pingroups, &drive_max); | ||
739 | #else | ||
740 | pr_warn("non Tegra20 platform requires pinmux devicetree node\n"); | ||
741 | #endif | ||
742 | |||
743 | for (i = 0; ; i++) { | ||
744 | res = platform_get_resource(pdev, IORESOURCE_MEM, i); | ||
745 | if (!res) | ||
746 | break; | ||
747 | } | ||
748 | nbanks = i; | ||
749 | |||
750 | for (i = 0; i < pingroup_max; i++) { | ||
751 | if (pingroups[i].tri_bank >= nbanks) { | ||
752 | dev_err(&pdev->dev, "pingroup %d: bad tri_bank\n", i); | ||
753 | config_bad = 1; | ||
754 | } | ||
755 | |||
756 | if (pingroups[i].mux_bank >= nbanks) { | ||
757 | dev_err(&pdev->dev, "pingroup %d: bad mux_bank\n", i); | ||
758 | config_bad = 1; | ||
759 | } | ||
760 | |||
761 | if (pingroups[i].pupd_bank >= nbanks) { | ||
762 | dev_err(&pdev->dev, "pingroup %d: bad pupd_bank\n", i); | ||
763 | config_bad = 1; | ||
764 | } | ||
765 | } | ||
766 | |||
767 | for (i = 0; i < drive_max; i++) { | ||
768 | if (drive_pingroups[i].reg_bank >= nbanks) { | ||
769 | dev_err(&pdev->dev, | ||
770 | "drive pingroup %d: bad reg_bank\n", i); | ||
771 | config_bad = 1; | ||
772 | } | ||
773 | } | ||
774 | |||
775 | if (config_bad) | ||
776 | return -ENODEV; | ||
777 | |||
778 | regs = devm_kzalloc(&pdev->dev, nbanks * sizeof(*regs), GFP_KERNEL); | ||
779 | if (!regs) { | ||
780 | dev_err(&pdev->dev, "Can't alloc regs pointer\n"); | ||
781 | return -ENODEV; | ||
782 | } | ||
783 | |||
784 | for (i = 0; i < nbanks; i++) { | ||
785 | res = platform_get_resource(pdev, IORESOURCE_MEM, i); | ||
786 | if (!res) { | ||
787 | dev_err(&pdev->dev, "Missing MEM resource\n"); | ||
788 | return -ENODEV; | ||
789 | } | ||
790 | |||
791 | if (!devm_request_mem_region(&pdev->dev, res->start, | ||
792 | resource_size(res), | ||
793 | dev_name(&pdev->dev))) { | ||
794 | dev_err(&pdev->dev, | ||
795 | "Couldn't request MEM resource %d\n", i); | ||
796 | return -ENODEV; | ||
797 | } | ||
798 | |||
799 | regs[i] = devm_ioremap(&pdev->dev, res->start, | ||
800 | resource_size(res)); | ||
801 | if (!regs) { | ||
802 | dev_err(&pdev->dev, "Couldn't ioremap regs %d\n", i); | ||
803 | return -ENODEV; | ||
804 | } | ||
805 | } | ||
806 | |||
807 | return 0; | ||
808 | } | ||
809 | |||
810 | static struct platform_driver tegra_pinmux_driver = { | ||
811 | .driver = { | ||
812 | .name = "tegra-pinmux-disabled", | ||
813 | .owner = THIS_MODULE, | ||
814 | .of_match_table = tegra_pinmux_of_match, | ||
815 | }, | ||
816 | .probe = tegra_pinmux_probe, | ||
817 | }; | ||
818 | |||
819 | static int __init tegra_pinmux_init(void) | ||
820 | { | ||
821 | return platform_driver_register(&tegra_pinmux_driver); | ||
822 | } | ||
823 | postcore_initcall(tegra_pinmux_init); | ||
824 | |||
825 | #ifdef CONFIG_DEBUG_FS | ||
826 | |||
827 | #include <linux/debugfs.h> | ||
828 | #include <linux/seq_file.h> | ||
829 | |||
830 | static void dbg_pad_field(struct seq_file *s, int len) | ||
831 | { | ||
832 | seq_putc(s, ','); | ||
833 | |||
834 | while (len-- > -1) | ||
835 | seq_putc(s, ' '); | ||
836 | } | ||
837 | |||
838 | static int dbg_pinmux_show(struct seq_file *s, void *unused) | ||
839 | { | ||
840 | int i; | ||
841 | int len; | ||
842 | |||
843 | for (i = 0; i < pingroup_max; i++) { | ||
844 | unsigned long reg; | ||
845 | unsigned long tri; | ||
846 | unsigned long mux; | ||
847 | unsigned long pupd; | ||
848 | |||
849 | seq_printf(s, "\t{TEGRA_PINGROUP_%s", pingroups[i].name); | ||
850 | len = strlen(pingroups[i].name); | ||
851 | dbg_pad_field(s, 5 - len); | ||
852 | |||
853 | if (pingroups[i].mux_reg < 0) { | ||
854 | seq_printf(s, "TEGRA_MUX_NONE"); | ||
855 | len = strlen("NONE"); | ||
856 | } else { | ||
857 | reg = pg_readl(pingroups[i].mux_bank, | ||
858 | pingroups[i].mux_reg); | ||
859 | mux = (reg >> pingroups[i].mux_bit) & 0x3; | ||
860 | if (pingroups[i].funcs[mux] == TEGRA_MUX_RSVD) { | ||
861 | seq_printf(s, "TEGRA_MUX_RSVD%1lu", mux+1); | ||
862 | len = 5; | ||
863 | } else { | ||
864 | seq_printf(s, "TEGRA_MUX_%s", | ||
865 | tegra_mux_names[pingroups[i].funcs[mux]]); | ||
866 | len = strlen(tegra_mux_names[pingroups[i].funcs[mux]]); | ||
867 | } | ||
868 | } | ||
869 | dbg_pad_field(s, 13-len); | ||
870 | |||
871 | if (pingroups[i].pupd_reg < 0) { | ||
872 | seq_printf(s, "TEGRA_PUPD_NORMAL"); | ||
873 | len = strlen("NORMAL"); | ||
874 | } else { | ||
875 | reg = pg_readl(pingroups[i].pupd_bank, | ||
876 | pingroups[i].pupd_reg); | ||
877 | pupd = (reg >> pingroups[i].pupd_bit) & 0x3; | ||
878 | seq_printf(s, "TEGRA_PUPD_%s", pupd_name(pupd)); | ||
879 | len = strlen(pupd_name(pupd)); | ||
880 | } | ||
881 | dbg_pad_field(s, 9 - len); | ||
882 | |||
883 | if (pingroups[i].tri_reg < 0) { | ||
884 | seq_printf(s, "TEGRA_TRI_NORMAL"); | ||
885 | } else { | ||
886 | reg = pg_readl(pingroups[i].tri_bank, | ||
887 | pingroups[i].tri_reg); | ||
888 | tri = (reg >> pingroups[i].tri_bit) & 0x1; | ||
889 | |||
890 | seq_printf(s, "TEGRA_TRI_%s", tri_name(tri)); | ||
891 | } | ||
892 | seq_printf(s, "},\n"); | ||
893 | } | ||
894 | return 0; | ||
895 | } | ||
896 | |||
897 | static int dbg_pinmux_open(struct inode *inode, struct file *file) | ||
898 | { | ||
899 | return single_open(file, dbg_pinmux_show, &inode->i_private); | ||
900 | } | ||
901 | |||
902 | static const struct file_operations debug_fops = { | ||
903 | .open = dbg_pinmux_open, | ||
904 | .read = seq_read, | ||
905 | .llseek = seq_lseek, | ||
906 | .release = single_release, | ||
907 | }; | ||
908 | |||
909 | static int dbg_drive_pinmux_show(struct seq_file *s, void *unused) | ||
910 | { | ||
911 | int i; | ||
912 | int len; | ||
913 | |||
914 | for (i = 0; i < drive_max; i++) { | ||
915 | u32 reg; | ||
916 | |||
917 | seq_printf(s, "\t{TEGRA_DRIVE_PINGROUP_%s", | ||
918 | drive_pingroups[i].name); | ||
919 | len = strlen(drive_pingroups[i].name); | ||
920 | dbg_pad_field(s, 7 - len); | ||
921 | |||
922 | |||
923 | reg = pg_readl(drive_pingroups[i].reg_bank, | ||
924 | drive_pingroups[i].reg); | ||
925 | if (HSM_EN(reg)) { | ||
926 | seq_printf(s, "TEGRA_HSM_ENABLE"); | ||
927 | len = 16; | ||
928 | } else { | ||
929 | seq_printf(s, "TEGRA_HSM_DISABLE"); | ||
930 | len = 17; | ||
931 | } | ||
932 | dbg_pad_field(s, 17 - len); | ||
933 | |||
934 | if (SCHMT_EN(reg)) { | ||
935 | seq_printf(s, "TEGRA_SCHMITT_ENABLE"); | ||
936 | len = 21; | ||
937 | } else { | ||
938 | seq_printf(s, "TEGRA_SCHMITT_DISABLE"); | ||
939 | len = 22; | ||
940 | } | ||
941 | dbg_pad_field(s, 22 - len); | ||
942 | |||
943 | seq_printf(s, "TEGRA_DRIVE_%s", drive_name(LPMD(reg))); | ||
944 | len = strlen(drive_name(LPMD(reg))); | ||
945 | dbg_pad_field(s, 5 - len); | ||
946 | |||
947 | seq_printf(s, "TEGRA_PULL_%d", DRVDN(reg)); | ||
948 | len = DRVDN(reg) < 10 ? 1 : 2; | ||
949 | dbg_pad_field(s, 2 - len); | ||
950 | |||
951 | seq_printf(s, "TEGRA_PULL_%d", DRVUP(reg)); | ||
952 | len = DRVUP(reg) < 10 ? 1 : 2; | ||
953 | dbg_pad_field(s, 2 - len); | ||
954 | |||
955 | seq_printf(s, "TEGRA_SLEW_%s", slew_name(SLWR(reg))); | ||
956 | len = strlen(slew_name(SLWR(reg))); | ||
957 | dbg_pad_field(s, 7 - len); | ||
958 | |||
959 | seq_printf(s, "TEGRA_SLEW_%s", slew_name(SLWF(reg))); | ||
960 | |||
961 | seq_printf(s, "},\n"); | ||
962 | } | ||
963 | return 0; | ||
964 | } | ||
965 | |||
966 | static int dbg_drive_pinmux_open(struct inode *inode, struct file *file) | ||
967 | { | ||
968 | return single_open(file, dbg_drive_pinmux_show, &inode->i_private); | ||
969 | } | ||
970 | |||
971 | static const struct file_operations debug_drive_fops = { | ||
972 | .open = dbg_drive_pinmux_open, | ||
973 | .read = seq_read, | ||
974 | .llseek = seq_lseek, | ||
975 | .release = single_release, | ||
976 | }; | ||
977 | |||
978 | static int __init tegra_pinmux_debuginit(void) | ||
979 | { | ||
980 | (void) debugfs_create_file("tegra_pinmux", S_IRUGO, | ||
981 | NULL, NULL, &debug_fops); | ||
982 | (void) debugfs_create_file("tegra_pinmux_drive", S_IRUGO, | ||
983 | NULL, NULL, &debug_drive_fops); | ||
984 | return 0; | ||
985 | } | ||
986 | late_initcall(tegra_pinmux_debuginit); | ||
987 | #endif | ||