blob: 45ebd8ceccca8e6378f22d859b78bbb51d943c1f [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>
Peter De Schrijver6996e082011-12-14 17:03:22 +020024#include <linux/of_device.h>
Erik Gillinga4417c82010-02-23 18:46:37 -080025
26#include <mach/iomap.h>
27#include <mach/pinmux.h>
28
Erik Gillinga4417c82010-02-23 18:46:37 -080029#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
Peter De Schrijver6996e082011-12-14 17:03:22 +020037static const struct tegra_pingroup_desc *pingroups;
38static const struct tegra_drive_pingroup_desc *drive_pingroups;
39static int pingroup_max;
40static int drive_max;
Erik Gillinga4417c82010-02-23 18:46:37 -080041
42static 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",
Colin Crossc5f04b82010-07-09 15:13:52 -0700103 [TEGRA_MUX_SAFE] = "<safe>",
Erik Gillinga4417c82010-02-23 18:46:37 -0800104};
105
106static const char *tegra_drive_names[TEGRA_MAX_DRIVE] = {
107 [TEGRA_DRIVE_DIV_8] = "DIV_8",
108 [TEGRA_DRIVE_DIV_4] = "DIV_4",
109 [TEGRA_DRIVE_DIV_2] = "DIV_2",
110 [TEGRA_DRIVE_DIV_1] = "DIV_1",
111};
112
113static const char *tegra_slew_names[TEGRA_MAX_SLEW] = {
114 [TEGRA_SLEW_FASTEST] = "FASTEST",
115 [TEGRA_SLEW_FAST] = "FAST",
116 [TEGRA_SLEW_SLOW] = "SLOW",
117 [TEGRA_SLEW_SLOWEST] = "SLOWEST",
118};
119
120static DEFINE_SPINLOCK(mux_lock);
121
Peter De Schrijver6996e082011-12-14 17:03:22 +0200122static const char *pingroup_name(int pg)
Erik Gillinga4417c82010-02-23 18:46:37 -0800123{
Peter De Schrijver6996e082011-12-14 17:03:22 +0200124 if (pg < 0 || pg >= pingroup_max)
Erik Gillinga4417c82010-02-23 18:46:37 -0800125 return "<UNKNOWN>";
126
127 return pingroups[pg].name;
128}
129
130static const char *func_name(enum tegra_mux_func func)
131{
132 if (func == TEGRA_MUX_RSVD1)
133 return "RSVD1";
134
135 if (func == TEGRA_MUX_RSVD2)
136 return "RSVD2";
137
138 if (func == TEGRA_MUX_RSVD3)
139 return "RSVD3";
140
141 if (func == TEGRA_MUX_RSVD4)
142 return "RSVD4";
143
144 if (func == TEGRA_MUX_NONE)
145 return "NONE";
146
147 if (func < 0 || func >= TEGRA_MAX_MUX)
148 return "<UNKNOWN>";
149
150 return tegra_mux_names[func];
151}
152
153
154static const char *tri_name(unsigned long val)
155{
156 return val ? "TRISTATE" : "NORMAL";
157}
158
159static const char *pupd_name(unsigned long val)
160{
161 switch (val) {
162 case 0:
163 return "NORMAL";
164
165 case 1:
166 return "PULL_DOWN";
167
168 case 2:
169 return "PULL_UP";
170
171 default:
172 return "RSVD";
173 }
174}
175
Stephen Warren48f2ece2011-10-12 09:54:27 -0600176static int nbanks;
177static void __iomem **regs;
Erik Gillinga4417c82010-02-23 18:46:37 -0800178
Stephen Warren48f2ece2011-10-12 09:54:27 -0600179static inline u32 pg_readl(u32 bank, u32 reg)
Erik Gillinga4417c82010-02-23 18:46:37 -0800180{
Stephen Warren48f2ece2011-10-12 09:54:27 -0600181 return readl(regs[bank] + reg);
Erik Gillinga4417c82010-02-23 18:46:37 -0800182}
183
Stephen Warren48f2ece2011-10-12 09:54:27 -0600184static inline void pg_writel(u32 val, u32 bank, u32 reg)
Erik Gillinga4417c82010-02-23 18:46:37 -0800185{
Stephen Warren48f2ece2011-10-12 09:54:27 -0600186 writel(val, regs[bank] + reg);
Erik Gillinga4417c82010-02-23 18:46:37 -0800187}
188
Colin Crossc5f04b82010-07-09 15:13:52 -0700189static int tegra_pinmux_set_func(const struct tegra_pingroup_config *config)
Erik Gillinga4417c82010-02-23 18:46:37 -0800190{
191 int mux = -1;
192 int i;
193 unsigned long reg;
194 unsigned long flags;
Peter De Schrijver6996e082011-12-14 17:03:22 +0200195 int pg = config->pingroup;
Colin Crossc5f04b82010-07-09 15:13:52 -0700196 enum tegra_mux_func func = config->func;
Erik Gillinga4417c82010-02-23 18:46:37 -0800197
Peter De Schrijver6996e082011-12-14 17:03:22 +0200198 if (pg < 0 || pg >= pingroup_max)
Erik Gillinga4417c82010-02-23 18:46:37 -0800199 return -ERANGE;
200
Colin Crossc5f04b82010-07-09 15:13:52 -0700201 if (pingroups[pg].mux_reg < 0)
Erik Gillinga4417c82010-02-23 18:46:37 -0800202 return -EINVAL;
203
204 if (func < 0)
205 return -ERANGE;
206
Colin Crossc5f04b82010-07-09 15:13:52 -0700207 if (func == TEGRA_MUX_SAFE)
208 func = pingroups[pg].func_safe;
209
Erik Gillinga4417c82010-02-23 18:46:37 -0800210 if (func & TEGRA_MUX_RSVD) {
211 mux = func & 0x3;
212 } else {
213 for (i = 0; i < 4; i++) {
214 if (pingroups[pg].funcs[i] == func) {
215 mux = i;
216 break;
217 }
218 }
219 }
220
221 if (mux < 0)
222 return -EINVAL;
223
224 spin_lock_irqsave(&mux_lock, flags);
225
Stephen Warren48f2ece2011-10-12 09:54:27 -0600226 reg = pg_readl(pingroups[pg].mux_bank, pingroups[pg].mux_reg);
Erik Gillinga4417c82010-02-23 18:46:37 -0800227 reg &= ~(0x3 << pingroups[pg].mux_bit);
228 reg |= mux << pingroups[pg].mux_bit;
Stephen Warren48f2ece2011-10-12 09:54:27 -0600229 pg_writel(reg, pingroups[pg].mux_bank, pingroups[pg].mux_reg);
Erik Gillinga4417c82010-02-23 18:46:37 -0800230
231 spin_unlock_irqrestore(&mux_lock, flags);
232
233 return 0;
234}
235
Peter De Schrijver6996e082011-12-14 17:03:22 +0200236int tegra_pinmux_set_tristate(int pg, enum tegra_tristate tristate)
Erik Gillinga4417c82010-02-23 18:46:37 -0800237{
238 unsigned long reg;
239 unsigned long flags;
240
Peter De Schrijver6996e082011-12-14 17:03:22 +0200241 if (pg < 0 || pg >= pingroup_max)
Erik Gillinga4417c82010-02-23 18:46:37 -0800242 return -ERANGE;
243
Colin Crossc5f04b82010-07-09 15:13:52 -0700244 if (pingroups[pg].tri_reg < 0)
Erik Gillinga4417c82010-02-23 18:46:37 -0800245 return -EINVAL;
246
247 spin_lock_irqsave(&mux_lock, flags);
248
Stephen Warren48f2ece2011-10-12 09:54:27 -0600249 reg = pg_readl(pingroups[pg].tri_bank, pingroups[pg].tri_reg);
Erik Gillinga4417c82010-02-23 18:46:37 -0800250 reg &= ~(0x1 << pingroups[pg].tri_bit);
251 if (tristate)
252 reg |= 1 << pingroups[pg].tri_bit;
Stephen Warren48f2ece2011-10-12 09:54:27 -0600253 pg_writel(reg, pingroups[pg].tri_bank, pingroups[pg].tri_reg);
Erik Gillinga4417c82010-02-23 18:46:37 -0800254
255 spin_unlock_irqrestore(&mux_lock, flags);
256
257 return 0;
258}
259
Peter De Schrijver6996e082011-12-14 17:03:22 +0200260int tegra_pinmux_set_pullupdown(int pg, enum tegra_pullupdown pupd)
Erik Gillinga4417c82010-02-23 18:46:37 -0800261{
262 unsigned long reg;
263 unsigned long flags;
264
Peter De Schrijver6996e082011-12-14 17:03:22 +0200265 if (pg < 0 || pg >= pingroup_max)
Erik Gillinga4417c82010-02-23 18:46:37 -0800266 return -ERANGE;
267
Colin Crossc5f04b82010-07-09 15:13:52 -0700268 if (pingroups[pg].pupd_reg < 0)
Erik Gillinga4417c82010-02-23 18:46:37 -0800269 return -EINVAL;
270
271 if (pupd != TEGRA_PUPD_NORMAL &&
272 pupd != TEGRA_PUPD_PULL_DOWN &&
273 pupd != TEGRA_PUPD_PULL_UP)
274 return -EINVAL;
275
276
277 spin_lock_irqsave(&mux_lock, flags);
278
Stephen Warren48f2ece2011-10-12 09:54:27 -0600279 reg = pg_readl(pingroups[pg].pupd_bank, pingroups[pg].pupd_reg);
Erik Gillinga4417c82010-02-23 18:46:37 -0800280 reg &= ~(0x3 << pingroups[pg].pupd_bit);
281 reg |= pupd << pingroups[pg].pupd_bit;
Stephen Warren48f2ece2011-10-12 09:54:27 -0600282 pg_writel(reg, pingroups[pg].pupd_bank, pingroups[pg].pupd_reg);
Erik Gillinga4417c82010-02-23 18:46:37 -0800283
284 spin_unlock_irqrestore(&mux_lock, flags);
285
286 return 0;
287}
288
Colin Crossc5f04b82010-07-09 15:13:52 -0700289static void tegra_pinmux_config_pingroup(const struct tegra_pingroup_config *config)
Erik Gillinga4417c82010-02-23 18:46:37 -0800290{
Peter De Schrijver6996e082011-12-14 17:03:22 +0200291 int pingroup = config->pingroup;
Colin Crossc5f04b82010-07-09 15:13:52 -0700292 enum tegra_mux_func func = config->func;
293 enum tegra_pullupdown pupd = config->pupd;
294 enum tegra_tristate tristate = config->tristate;
Erik Gillinga4417c82010-02-23 18:46:37 -0800295 int err;
296
Colin Crossc5f04b82010-07-09 15:13:52 -0700297 if (pingroups[pingroup].mux_reg >= 0) {
298 err = tegra_pinmux_set_func(config);
Erik Gillinga4417c82010-02-23 18:46:37 -0800299 if (err < 0)
300 pr_err("pinmux: can't set pingroup %s func to %s: %d\n",
301 pingroup_name(pingroup), func_name(func), err);
302 }
303
Colin Crossc5f04b82010-07-09 15:13:52 -0700304 if (pingroups[pingroup].pupd_reg >= 0) {
Erik Gillinga4417c82010-02-23 18:46:37 -0800305 err = tegra_pinmux_set_pullupdown(pingroup, pupd);
306 if (err < 0)
307 pr_err("pinmux: can't set pingroup %s pullupdown to %s: %d\n",
308 pingroup_name(pingroup), pupd_name(pupd), err);
309 }
310
Colin Crossc5f04b82010-07-09 15:13:52 -0700311 if (pingroups[pingroup].tri_reg >= 0) {
Erik Gillinga4417c82010-02-23 18:46:37 -0800312 err = tegra_pinmux_set_tristate(pingroup, tristate);
313 if (err < 0)
314 pr_err("pinmux: can't set pingroup %s tristate to %s: %d\n",
315 pingroup_name(pingroup), tri_name(func), err);
316 }
317}
318
Colin Crossc5f04b82010-07-09 15:13:52 -0700319void tegra_pinmux_config_table(const struct tegra_pingroup_config *config, int len)
Erik Gillinga4417c82010-02-23 18:46:37 -0800320{
321 int i;
322
323 for (i = 0; i < len; i++)
Colin Crossc5f04b82010-07-09 15:13:52 -0700324 tegra_pinmux_config_pingroup(&config[i]);
Erik Gillinga4417c82010-02-23 18:46:37 -0800325}
326
Peter De Schrijver6996e082011-12-14 17:03:22 +0200327static const char *drive_pinmux_name(int pg)
Erik Gillinga4417c82010-02-23 18:46:37 -0800328{
Peter De Schrijver6996e082011-12-14 17:03:22 +0200329 if (pg < 0 || pg >= drive_max)
Erik Gillinga4417c82010-02-23 18:46:37 -0800330 return "<UNKNOWN>";
331
332 return drive_pingroups[pg].name;
333}
334
335static const char *enable_name(unsigned long val)
336{
337 return val ? "ENABLE" : "DISABLE";
338}
339
340static const char *drive_name(unsigned long val)
341{
342 if (val >= TEGRA_MAX_DRIVE)
343 return "<UNKNOWN>";
344
345 return tegra_drive_names[val];
346}
347
348static const char *slew_name(unsigned long val)
349{
350 if (val >= TEGRA_MAX_SLEW)
351 return "<UNKNOWN>";
352
353 return tegra_slew_names[val];
354}
355
Peter De Schrijver6996e082011-12-14 17:03:22 +0200356static int tegra_drive_pinmux_set_hsm(int pg, enum tegra_hsm hsm)
Erik Gillinga4417c82010-02-23 18:46:37 -0800357{
358 unsigned long flags;
359 u32 reg;
Peter De Schrijver6996e082011-12-14 17:03:22 +0200360 if (pg < 0 || pg >= drive_max)
Erik Gillinga4417c82010-02-23 18:46:37 -0800361 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
Peter De Schrijver6996e082011-12-14 17:03:22 +0200380static int tegra_drive_pinmux_set_schmitt(int pg, enum tegra_schmitt schmitt)
Erik Gillinga4417c82010-02-23 18:46:37 -0800381{
382 unsigned long flags;
383 u32 reg;
Peter De Schrijver6996e082011-12-14 17:03:22 +0200384 if (pg < 0 || pg >= drive_max)
Erik Gillinga4417c82010-02-23 18:46:37 -0800385 return -ERANGE;
386
387 if (schmitt != TEGRA_SCHMITT_ENABLE && schmitt != TEGRA_SCHMITT_DISABLE)
388 return -EINVAL;
389
390 spin_lock_irqsave(&mux_lock, flags);
391
Stephen Warren48f2ece2011-10-12 09:54:27 -0600392 reg = pg_readl(drive_pingroups[pg].reg_bank, drive_pingroups[pg].reg);
Erik Gillinga4417c82010-02-23 18:46:37 -0800393 if (schmitt == TEGRA_SCHMITT_ENABLE)
394 reg |= (1 << 3);
395 else
396 reg &= ~(1 << 3);
Stephen Warren48f2ece2011-10-12 09:54:27 -0600397 pg_writel(reg, drive_pingroups[pg].reg_bank, drive_pingroups[pg].reg);
Erik Gillinga4417c82010-02-23 18:46:37 -0800398
399 spin_unlock_irqrestore(&mux_lock, flags);
400
401 return 0;
402}
403
Peter De Schrijver6996e082011-12-14 17:03:22 +0200404static int tegra_drive_pinmux_set_drive(int pg, enum tegra_drive drive)
Erik Gillinga4417c82010-02-23 18:46:37 -0800405{
406 unsigned long flags;
407 u32 reg;
Peter De Schrijver6996e082011-12-14 17:03:22 +0200408 if (pg < 0 || pg >= drive_max)
Erik Gillinga4417c82010-02-23 18:46:37 -0800409 return -ERANGE;
410
411 if (drive < 0 || drive >= TEGRA_MAX_DRIVE)
412 return -EINVAL;
413
414 spin_lock_irqsave(&mux_lock, flags);
415
Stephen Warren48f2ece2011-10-12 09:54:27 -0600416 reg = pg_readl(drive_pingroups[pg].reg_bank, drive_pingroups[pg].reg);
Erik Gillinga4417c82010-02-23 18:46:37 -0800417 reg &= ~(0x3 << 4);
418 reg |= drive << 4;
Stephen Warren48f2ece2011-10-12 09:54:27 -0600419 pg_writel(reg, drive_pingroups[pg].reg_bank, drive_pingroups[pg].reg);
Erik Gillinga4417c82010-02-23 18:46:37 -0800420
421 spin_unlock_irqrestore(&mux_lock, flags);
422
423 return 0;
424}
425
Peter De Schrijver6996e082011-12-14 17:03:22 +0200426static int tegra_drive_pinmux_set_pull_down(int pg,
Erik Gillinga4417c82010-02-23 18:46:37 -0800427 enum tegra_pull_strength pull_down)
428{
429 unsigned long flags;
430 u32 reg;
Peter De Schrijver6996e082011-12-14 17:03:22 +0200431 if (pg < 0 || pg >= drive_max)
Erik Gillinga4417c82010-02-23 18:46:37 -0800432 return -ERANGE;
433
434 if (pull_down < 0 || pull_down >= TEGRA_MAX_PULL)
435 return -EINVAL;
436
437 spin_lock_irqsave(&mux_lock, flags);
438
Stephen Warren48f2ece2011-10-12 09:54:27 -0600439 reg = pg_readl(drive_pingroups[pg].reg_bank, drive_pingroups[pg].reg);
Erik Gillinga4417c82010-02-23 18:46:37 -0800440 reg &= ~(0x1f << 12);
441 reg |= pull_down << 12;
Stephen Warren48f2ece2011-10-12 09:54:27 -0600442 pg_writel(reg, drive_pingroups[pg].reg_bank, drive_pingroups[pg].reg);
Erik Gillinga4417c82010-02-23 18:46:37 -0800443
444 spin_unlock_irqrestore(&mux_lock, flags);
445
446 return 0;
447}
448
Peter De Schrijver6996e082011-12-14 17:03:22 +0200449static int tegra_drive_pinmux_set_pull_up(int pg,
Erik Gillinga4417c82010-02-23 18:46:37 -0800450 enum tegra_pull_strength pull_up)
451{
452 unsigned long flags;
453 u32 reg;
Peter De Schrijver6996e082011-12-14 17:03:22 +0200454 if (pg < 0 || pg >= drive_max)
Erik Gillinga4417c82010-02-23 18:46:37 -0800455 return -ERANGE;
456
457 if (pull_up < 0 || pull_up >= TEGRA_MAX_PULL)
458 return -EINVAL;
459
460 spin_lock_irqsave(&mux_lock, flags);
461
Stephen Warren48f2ece2011-10-12 09:54:27 -0600462 reg = pg_readl(drive_pingroups[pg].reg_bank, drive_pingroups[pg].reg);
Erik Gillinga4417c82010-02-23 18:46:37 -0800463 reg &= ~(0x1f << 12);
464 reg |= pull_up << 12;
Stephen Warren48f2ece2011-10-12 09:54:27 -0600465 pg_writel(reg, drive_pingroups[pg].reg_bank, drive_pingroups[pg].reg);
Erik Gillinga4417c82010-02-23 18:46:37 -0800466
467 spin_unlock_irqrestore(&mux_lock, flags);
468
469 return 0;
470}
471
Peter De Schrijver6996e082011-12-14 17:03:22 +0200472static int tegra_drive_pinmux_set_slew_rising(int pg,
Erik Gillinga4417c82010-02-23 18:46:37 -0800473 enum tegra_slew slew_rising)
474{
475 unsigned long flags;
476 u32 reg;
Peter De Schrijver6996e082011-12-14 17:03:22 +0200477 if (pg < 0 || pg >= drive_max)
Erik Gillinga4417c82010-02-23 18:46:37 -0800478 return -ERANGE;
479
480 if (slew_rising < 0 || slew_rising >= TEGRA_MAX_SLEW)
481 return -EINVAL;
482
483 spin_lock_irqsave(&mux_lock, flags);
484
Stephen Warren48f2ece2011-10-12 09:54:27 -0600485 reg = pg_readl(drive_pingroups[pg].reg_bank, drive_pingroups[pg].reg);
Erik Gillinga4417c82010-02-23 18:46:37 -0800486 reg &= ~(0x3 << 28);
487 reg |= slew_rising << 28;
Stephen Warren48f2ece2011-10-12 09:54:27 -0600488 pg_writel(reg, drive_pingroups[pg].reg_bank, drive_pingroups[pg].reg);
Erik Gillinga4417c82010-02-23 18:46:37 -0800489
490 spin_unlock_irqrestore(&mux_lock, flags);
491
492 return 0;
493}
494
Peter De Schrijver6996e082011-12-14 17:03:22 +0200495static int tegra_drive_pinmux_set_slew_falling(int pg,
Erik Gillinga4417c82010-02-23 18:46:37 -0800496 enum tegra_slew slew_falling)
497{
498 unsigned long flags;
499 u32 reg;
Peter De Schrijver6996e082011-12-14 17:03:22 +0200500 if (pg < 0 || pg >= drive_max)
Erik Gillinga4417c82010-02-23 18:46:37 -0800501 return -ERANGE;
502
503 if (slew_falling < 0 || slew_falling >= TEGRA_MAX_SLEW)
504 return -EINVAL;
505
506 spin_lock_irqsave(&mux_lock, flags);
507
Stephen Warren48f2ece2011-10-12 09:54:27 -0600508 reg = pg_readl(drive_pingroups[pg].reg_bank, drive_pingroups[pg].reg);
Erik Gillinga4417c82010-02-23 18:46:37 -0800509 reg &= ~(0x3 << 30);
510 reg |= slew_falling << 30;
Stephen Warren48f2ece2011-10-12 09:54:27 -0600511 pg_writel(reg, drive_pingroups[pg].reg_bank, drive_pingroups[pg].reg);
Erik Gillinga4417c82010-02-23 18:46:37 -0800512
513 spin_unlock_irqrestore(&mux_lock, flags);
514
515 return 0;
516}
517
Peter De Schrijver6996e082011-12-14 17:03:22 +0200518static void tegra_drive_pinmux_config_pingroup(int pingroup,
Erik Gillinga4417c82010-02-23 18:46:37 -0800519 enum tegra_hsm hsm,
520 enum tegra_schmitt schmitt,
521 enum tegra_drive drive,
522 enum tegra_pull_strength pull_down,
523 enum tegra_pull_strength pull_up,
524 enum tegra_slew slew_rising,
525 enum tegra_slew slew_falling)
526{
527 int err;
528
529 err = tegra_drive_pinmux_set_hsm(pingroup, hsm);
530 if (err < 0)
531 pr_err("pinmux: can't set pingroup %s hsm to %s: %d\n",
532 drive_pinmux_name(pingroup),
533 enable_name(hsm), err);
534
535 err = tegra_drive_pinmux_set_schmitt(pingroup, schmitt);
536 if (err < 0)
537 pr_err("pinmux: can't set pingroup %s schmitt to %s: %d\n",
538 drive_pinmux_name(pingroup),
539 enable_name(schmitt), err);
540
541 err = tegra_drive_pinmux_set_drive(pingroup, drive);
542 if (err < 0)
543 pr_err("pinmux: can't set pingroup %s drive to %s: %d\n",
544 drive_pinmux_name(pingroup),
545 drive_name(drive), err);
546
547 err = tegra_drive_pinmux_set_pull_down(pingroup, pull_down);
548 if (err < 0)
549 pr_err("pinmux: can't set pingroup %s pull down to %d: %d\n",
550 drive_pinmux_name(pingroup),
551 pull_down, err);
552
553 err = tegra_drive_pinmux_set_pull_up(pingroup, pull_up);
554 if (err < 0)
555 pr_err("pinmux: can't set pingroup %s pull up to %d: %d\n",
556 drive_pinmux_name(pingroup),
557 pull_up, err);
558
559 err = tegra_drive_pinmux_set_slew_rising(pingroup, slew_rising);
560 if (err < 0)
561 pr_err("pinmux: can't set pingroup %s rising slew to %s: %d\n",
562 drive_pinmux_name(pingroup),
563 slew_name(slew_rising), err);
564
565 err = tegra_drive_pinmux_set_slew_falling(pingroup, slew_falling);
566 if (err < 0)
567 pr_err("pinmux: can't set pingroup %s falling slew to %s: %d\n",
568 drive_pinmux_name(pingroup),
569 slew_name(slew_falling), err);
570}
571
572void tegra_drive_pinmux_config_table(struct tegra_drive_pingroup_config *config,
573 int len)
574{
575 int i;
576
577 for (i = 0; i < len; i++)
578 tegra_drive_pinmux_config_pingroup(config[i].pingroup,
579 config[i].hsm,
580 config[i].schmitt,
581 config[i].drive,
582 config[i].pull_down,
583 config[i].pull_up,
584 config[i].slew_rising,
585 config[i].slew_falling);
586}
587
Colin Crossc5f04b82010-07-09 15:13:52 -0700588void tegra_pinmux_set_safe_pinmux_table(const struct tegra_pingroup_config *config,
589 int len)
590{
591 int i;
592 struct tegra_pingroup_config c;
593
594 for (i = 0; i < len; i++) {
595 int err;
596 c = config[i];
Peter De Schrijver6996e082011-12-14 17:03:22 +0200597 if (c.pingroup < 0 || c.pingroup >= pingroup_max) {
Colin Crossc5f04b82010-07-09 15:13:52 -0700598 WARN_ON(1);
599 continue;
600 }
601 c.func = pingroups[c.pingroup].func_safe;
602 err = tegra_pinmux_set_func(&c);
603 if (err < 0)
604 pr_err("%s: tegra_pinmux_set_func returned %d setting "
605 "%s to %s\n", __func__, err,
606 pingroup_name(c.pingroup), func_name(c.func));
607 }
608}
609
610void tegra_pinmux_config_pinmux_table(const struct tegra_pingroup_config *config,
611 int len)
612{
613 int i;
614
615 for (i = 0; i < len; i++) {
616 int err;
617 if (config[i].pingroup < 0 ||
Peter De Schrijver6996e082011-12-14 17:03:22 +0200618 config[i].pingroup >= pingroup_max) {
Colin Crossc5f04b82010-07-09 15:13:52 -0700619 WARN_ON(1);
620 continue;
621 }
622 err = tegra_pinmux_set_func(&config[i]);
623 if (err < 0)
624 pr_err("%s: tegra_pinmux_set_func returned %d setting "
625 "%s to %s\n", __func__, err,
626 pingroup_name(config[i].pingroup),
627 func_name(config[i].func));
628 }
629}
630
631void tegra_pinmux_config_tristate_table(const struct tegra_pingroup_config *config,
632 int len, enum tegra_tristate tristate)
633{
634 int i;
635 int err;
Peter De Schrijver6996e082011-12-14 17:03:22 +0200636 int pingroup;
Colin Crossc5f04b82010-07-09 15:13:52 -0700637
638 for (i = 0; i < len; i++) {
639 pingroup = config[i].pingroup;
640 if (pingroups[pingroup].tri_reg >= 0) {
641 err = tegra_pinmux_set_tristate(pingroup, tristate);
642 if (err < 0)
643 pr_err("pinmux: can't set pingroup %s tristate"
644 " to %s: %d\n", pingroup_name(pingroup),
645 tri_name(tristate), err);
646 }
647 }
648}
649
650void tegra_pinmux_config_pullupdown_table(const struct tegra_pingroup_config *config,
651 int len, enum tegra_pullupdown pupd)
652{
653 int i;
654 int err;
Peter De Schrijver6996e082011-12-14 17:03:22 +0200655 int pingroup;
Colin Crossc5f04b82010-07-09 15:13:52 -0700656
657 for (i = 0; i < len; i++) {
658 pingroup = config[i].pingroup;
659 if (pingroups[pingroup].pupd_reg >= 0) {
660 err = tegra_pinmux_set_pullupdown(pingroup, pupd);
661 if (err < 0)
662 pr_err("pinmux: can't set pingroup %s pullupdown"
663 " to %s: %d\n", pingroup_name(pingroup),
664 pupd_name(pupd), err);
665 }
666 }
667}
Erik Gillinga4417c82010-02-23 18:46:37 -0800668
Peter De Schrijver6996e082011-12-14 17:03:22 +0200669static struct of_device_id tegra_pinmux_of_match[] __devinitdata = {
670 { .compatible = "nvidia,tegra20-pinmux", tegra20_pinmux_init },
671 { },
672};
673
Stephen Warren1ebc8492011-10-11 16:16:15 -0600674static int __devinit tegra_pinmux_probe(struct platform_device *pdev)
675{
Stephen Warren48f2ece2011-10-12 09:54:27 -0600676 struct resource *res;
677 int i;
678 int config_bad = 0;
Peter De Schrijver6996e082011-12-14 17:03:22 +0200679 const struct of_device_id *match;
680
681 match = of_match_device(tegra_pinmux_of_match, &pdev->dev);
682
683 if (match)
684 ((pinmux_init)(match->data))(&pingroups, &pingroup_max,
685 &drive_pingroups, &drive_max);
686#ifdef CONFIG_ARCH_TEGRA_2x_SOC
687 else
688 /* no device tree available, so we must be on tegra20 */
689 tegra20_pinmux_init(&pingroups, &pingroup_max,
690 &drive_pingroups, &drive_max);
691#else
692 pr_warn("non Tegra20 platform requires pinmux devicetree node\n");
693#endif
Stephen Warren48f2ece2011-10-12 09:54:27 -0600694
695 for (i = 0; ; i++) {
696 res = platform_get_resource(pdev, IORESOURCE_MEM, i);
697 if (!res)
698 break;
699 }
700 nbanks = i;
701
Peter De Schrijver6996e082011-12-14 17:03:22 +0200702 for (i = 0; i < pingroup_max; i++) {
Stephen Warren48f2ece2011-10-12 09:54:27 -0600703 if (pingroups[i].tri_bank >= nbanks) {
704 dev_err(&pdev->dev, "pingroup %d: bad tri_bank\n", i);
705 config_bad = 1;
706 }
707
708 if (pingroups[i].mux_bank >= nbanks) {
709 dev_err(&pdev->dev, "pingroup %d: bad mux_bank\n", i);
710 config_bad = 1;
711 }
712
713 if (pingroups[i].pupd_bank >= nbanks) {
714 dev_err(&pdev->dev, "pingroup %d: bad pupd_bank\n", i);
715 config_bad = 1;
716 }
717 }
718
Peter De Schrijver6996e082011-12-14 17:03:22 +0200719 for (i = 0; i < drive_max; i++) {
Stephen Warren48f2ece2011-10-12 09:54:27 -0600720 if (drive_pingroups[i].reg_bank >= nbanks) {
721 dev_err(&pdev->dev,
722 "drive pingroup %d: bad reg_bank\n", i);
723 config_bad = 1;
724 }
725 }
726
727 if (config_bad)
728 return -ENODEV;
729
730 regs = devm_kzalloc(&pdev->dev, nbanks * sizeof(*regs), GFP_KERNEL);
731 if (!regs) {
732 dev_err(&pdev->dev, "Can't alloc regs pointer\n");
733 return -ENODEV;
734 }
735
736 for (i = 0; i < nbanks; i++) {
737 res = platform_get_resource(pdev, IORESOURCE_MEM, i);
738 if (!res) {
739 dev_err(&pdev->dev, "Missing MEM resource\n");
740 return -ENODEV;
741 }
742
743 if (!devm_request_mem_region(&pdev->dev, res->start,
744 resource_size(res),
745 dev_name(&pdev->dev))) {
746 dev_err(&pdev->dev,
747 "Couldn't request MEM resource %d\n", i);
748 return -ENODEV;
749 }
750
751 regs[i] = devm_ioremap(&pdev->dev, res->start,
752 resource_size(res));
753 if (!regs) {
754 dev_err(&pdev->dev, "Couldn't ioremap regs %d\n", i);
755 return -ENODEV;
756 }
757 }
758
Stephen Warren1ebc8492011-10-11 16:16:15 -0600759 return 0;
760}
761
Stephen Warren1ebc8492011-10-11 16:16:15 -0600762static struct platform_driver tegra_pinmux_driver = {
763 .driver = {
764 .name = "tegra-pinmux",
765 .owner = THIS_MODULE,
766 .of_match_table = tegra_pinmux_of_match,
767 },
768 .probe = tegra_pinmux_probe,
769};
770
771static int __init tegra_pinmux_init(void)
772{
773 return platform_driver_register(&tegra_pinmux_driver);
774}
775postcore_initcall(tegra_pinmux_init);
776
Erik Gillinga4417c82010-02-23 18:46:37 -0800777#ifdef CONFIG_DEBUG_FS
778
779#include <linux/debugfs.h>
780#include <linux/seq_file.h>
781
782static void dbg_pad_field(struct seq_file *s, int len)
783{
784 seq_putc(s, ',');
785
786 while (len-- > -1)
787 seq_putc(s, ' ');
788}
789
790static int dbg_pinmux_show(struct seq_file *s, void *unused)
791{
792 int i;
793 int len;
794
Peter De Schrijver6996e082011-12-14 17:03:22 +0200795 for (i = 0; i < pingroup_max; i++) {
Stephen Warren48f2ece2011-10-12 09:54:27 -0600796 unsigned long reg;
Erik Gillinga4417c82010-02-23 18:46:37 -0800797 unsigned long tri;
798 unsigned long mux;
799 unsigned long pupd;
800
801 seq_printf(s, "\t{TEGRA_PINGROUP_%s", pingroups[i].name);
802 len = strlen(pingroups[i].name);
803 dbg_pad_field(s, 5 - len);
804
Colin Crossc5f04b82010-07-09 15:13:52 -0700805 if (pingroups[i].mux_reg < 0) {
Erik Gillinga4417c82010-02-23 18:46:37 -0800806 seq_printf(s, "TEGRA_MUX_NONE");
807 len = strlen("NONE");
808 } else {
Stephen Warren48f2ece2011-10-12 09:54:27 -0600809 reg = pg_readl(pingroups[i].mux_bank,
810 pingroups[i].mux_reg);
811 mux = (reg >> pingroups[i].mux_bit) & 0x3;
Erik Gillinga4417c82010-02-23 18:46:37 -0800812 if (pingroups[i].funcs[mux] == TEGRA_MUX_RSVD) {
813 seq_printf(s, "TEGRA_MUX_RSVD%1lu", mux+1);
814 len = 5;
815 } else {
816 seq_printf(s, "TEGRA_MUX_%s",
817 tegra_mux_names[pingroups[i].funcs[mux]]);
818 len = strlen(tegra_mux_names[pingroups[i].funcs[mux]]);
819 }
820 }
821 dbg_pad_field(s, 13-len);
822
Colin Crossc5f04b82010-07-09 15:13:52 -0700823 if (pingroups[i].pupd_reg < 0) {
Erik Gillinga4417c82010-02-23 18:46:37 -0800824 seq_printf(s, "TEGRA_PUPD_NORMAL");
825 len = strlen("NORMAL");
826 } else {
Stephen Warren48f2ece2011-10-12 09:54:27 -0600827 reg = pg_readl(pingroups[i].pupd_bank,
828 pingroups[i].pupd_reg);
829 pupd = (reg >> pingroups[i].pupd_bit) & 0x3;
Erik Gillinga4417c82010-02-23 18:46:37 -0800830 seq_printf(s, "TEGRA_PUPD_%s", pupd_name(pupd));
831 len = strlen(pupd_name(pupd));
832 }
833 dbg_pad_field(s, 9 - len);
834
Colin Crossc5f04b82010-07-09 15:13:52 -0700835 if (pingroups[i].tri_reg < 0) {
Erik Gillinga4417c82010-02-23 18:46:37 -0800836 seq_printf(s, "TEGRA_TRI_NORMAL");
837 } else {
Stephen Warren48f2ece2011-10-12 09:54:27 -0600838 reg = pg_readl(pingroups[i].tri_bank,
839 pingroups[i].tri_reg);
840 tri = (reg >> pingroups[i].tri_bit) & 0x1;
Erik Gillinga4417c82010-02-23 18:46:37 -0800841
842 seq_printf(s, "TEGRA_TRI_%s", tri_name(tri));
843 }
844 seq_printf(s, "},\n");
845 }
846 return 0;
847}
848
849static int dbg_pinmux_open(struct inode *inode, struct file *file)
850{
851 return single_open(file, dbg_pinmux_show, &inode->i_private);
852}
853
854static const struct file_operations debug_fops = {
855 .open = dbg_pinmux_open,
856 .read = seq_read,
857 .llseek = seq_lseek,
858 .release = single_release,
859};
860
861static int dbg_drive_pinmux_show(struct seq_file *s, void *unused)
862{
863 int i;
864 int len;
865
Peter De Schrijver6996e082011-12-14 17:03:22 +0200866 for (i = 0; i < drive_max; i++) {
Erik Gillinga4417c82010-02-23 18:46:37 -0800867 u32 reg;
868
869 seq_printf(s, "\t{TEGRA_DRIVE_PINGROUP_%s",
870 drive_pingroups[i].name);
871 len = strlen(drive_pingroups[i].name);
872 dbg_pad_field(s, 7 - len);
873
874
Stephen Warren48f2ece2011-10-12 09:54:27 -0600875 reg = pg_readl(drive_pingroups[i].reg_bank,
876 drive_pingroups[i].reg);
Erik Gillinga4417c82010-02-23 18:46:37 -0800877 if (HSM_EN(reg)) {
878 seq_printf(s, "TEGRA_HSM_ENABLE");
879 len = 16;
880 } else {
881 seq_printf(s, "TEGRA_HSM_DISABLE");
882 len = 17;
883 }
884 dbg_pad_field(s, 17 - len);
885
886 if (SCHMT_EN(reg)) {
887 seq_printf(s, "TEGRA_SCHMITT_ENABLE");
888 len = 21;
889 } else {
890 seq_printf(s, "TEGRA_SCHMITT_DISABLE");
891 len = 22;
892 }
893 dbg_pad_field(s, 22 - len);
894
895 seq_printf(s, "TEGRA_DRIVE_%s", drive_name(LPMD(reg)));
896 len = strlen(drive_name(LPMD(reg)));
897 dbg_pad_field(s, 5 - len);
898
899 seq_printf(s, "TEGRA_PULL_%d", DRVDN(reg));
900 len = DRVDN(reg) < 10 ? 1 : 2;
901 dbg_pad_field(s, 2 - len);
902
903 seq_printf(s, "TEGRA_PULL_%d", DRVUP(reg));
904 len = DRVUP(reg) < 10 ? 1 : 2;
905 dbg_pad_field(s, 2 - len);
906
907 seq_printf(s, "TEGRA_SLEW_%s", slew_name(SLWR(reg)));
908 len = strlen(slew_name(SLWR(reg)));
909 dbg_pad_field(s, 7 - len);
910
911 seq_printf(s, "TEGRA_SLEW_%s", slew_name(SLWF(reg)));
912
913 seq_printf(s, "},\n");
914 }
915 return 0;
916}
917
918static int dbg_drive_pinmux_open(struct inode *inode, struct file *file)
919{
920 return single_open(file, dbg_drive_pinmux_show, &inode->i_private);
921}
922
923static const struct file_operations debug_drive_fops = {
924 .open = dbg_drive_pinmux_open,
925 .read = seq_read,
926 .llseek = seq_lseek,
927 .release = single_release,
928};
929
930static int __init tegra_pinmux_debuginit(void)
931{
932 (void) debugfs_create_file("tegra_pinmux", S_IRUGO,
933 NULL, NULL, &debug_fops);
934 (void) debugfs_create_file("tegra_pinmux_drive", S_IRUGO,
935 NULL, NULL, &debug_drive_fops);
936 return 0;
937}
938late_initcall(tegra_pinmux_debuginit);
939#endif