Commit | Line | Data |
---|---|---|
1dbae815 TL |
1 | /* |
2 | * linux/arch/arm/mach-omap2/mux.c | |
3 | * | |
2351872c | 4 | * OMAP2 and OMAP3 pin multiplexing configurations |
1dbae815 | 5 | * |
9330899e TL |
6 | * Copyright (C) 2004 - 2008 Texas Instruments Inc. |
7 | * Copyright (C) 2003 - 2008 Nokia Corporation | |
1dbae815 | 8 | * |
9330899e | 9 | * Written by Tony Lindgren |
1dbae815 TL |
10 | * |
11 | * This program is free software; you can redistribute it and/or modify | |
12 | * it under the terms of the GNU General Public License as published by | |
13 | * the Free Software Foundation; either version 2 of the License, or | |
14 | * (at your option) any later version. | |
15 | * | |
16 | * This program is distributed in the hope that it will be useful, | |
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
19 | * GNU General Public License for more details. | |
20 | * | |
21 | * You should have received a copy of the GNU General Public License | |
22 | * along with this program; if not, write to the Free Software | |
23 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
24 | * | |
25 | */ | |
1dbae815 TL |
26 | #include <linux/module.h> |
27 | #include <linux/init.h> | |
fced80c7 | 28 | #include <linux/io.h> |
1dbae815 | 29 | #include <linux/spinlock.h> |
15ac7afe | 30 | #include <linux/list.h> |
4b715efc TL |
31 | #include <linux/ctype.h> |
32 | #include <linux/debugfs.h> | |
33 | #include <linux/seq_file.h> | |
34 | #include <linux/uaccess.h> | |
1dbae815 | 35 | |
fced80c7 RK |
36 | #include <asm/system.h> |
37 | ||
ce491cf8 TL |
38 | #include <plat/control.h> |
39 | #include <plat/mux.h> | |
1dbae815 | 40 | |
15ac7afe | 41 | #include "mux.h" |
1dbae815 | 42 | |
92c9f501 MR |
43 | #define OMAP_MUX_BASE_OFFSET 0x30 /* Offset from CTRL_BASE */ |
44 | #define OMAP_MUX_BASE_SZ 0x5ca | |
45 | ||
15ac7afe TL |
46 | struct omap_mux_entry { |
47 | struct omap_mux mux; | |
48 | struct list_head node; | |
49 | }; | |
50 | ||
4b715efc | 51 | static unsigned long mux_phys; |
92c9f501 MR |
52 | static void __iomem *mux_base; |
53 | ||
54 | static inline u16 omap_mux_read(u16 reg) | |
55 | { | |
56 | if (cpu_is_omap24xx()) | |
57 | return __raw_readb(mux_base + reg); | |
58 | else | |
59 | return __raw_readw(mux_base + reg); | |
60 | } | |
61 | ||
62 | static inline void omap_mux_write(u16 val, u16 reg) | |
63 | { | |
64 | if (cpu_is_omap24xx()) | |
65 | __raw_writeb(val, mux_base + reg); | |
66 | else | |
67 | __raw_writew(val, mux_base + reg); | |
68 | } | |
7d7f665d | 69 | |
15f45e6f | 70 | #if defined(CONFIG_ARCH_OMAP24XX) && defined(CONFIG_OMAP_MUX) |
15ac7afe TL |
71 | |
72 | static struct omap_mux_cfg arch_mux_cfg; | |
73 | ||
1dbae815 TL |
74 | /* NOTE: See mux.h for the enumeration */ |
75 | ||
9330899e | 76 | static struct pin_config __initdata_or_module omap24xx_pins[] = { |
1dbae815 TL |
77 | /* |
78 | * description mux mux pull pull debug | |
79 | * offset mode ena type | |
80 | */ | |
81 | ||
82 | /* 24xx I2C */ | |
83 | MUX_CFG_24XX("M19_24XX_I2C1_SCL", 0x111, 0, 0, 0, 1) | |
84 | MUX_CFG_24XX("L15_24XX_I2C1_SDA", 0x112, 0, 0, 0, 1) | |
7bbb3cc5 | 85 | MUX_CFG_24XX("J15_24XX_I2C2_SCL", 0x113, 0, 0, 1, 1) |
1dbae815 TL |
86 | MUX_CFG_24XX("H19_24XX_I2C2_SDA", 0x114, 0, 0, 0, 1) |
87 | ||
88 | /* Menelaus interrupt */ | |
89 | MUX_CFG_24XX("W19_24XX_SYS_NIRQ", 0x12c, 0, 1, 1, 1) | |
90 | ||
8d7f9f50 TL |
91 | /* 24xx clocks */ |
92 | MUX_CFG_24XX("W14_24XX_SYS_CLKOUT", 0x137, 0, 1, 1, 1) | |
93 | ||
7bbb3cc5 | 94 | /* 24xx GPMC chipselects, wait pin monitoring */ |
7d34f3b3 TL |
95 | MUX_CFG_24XX("E2_GPMC_NCS2", 0x08e, 0, 1, 1, 1) |
96 | MUX_CFG_24XX("L2_GPMC_NCS7", 0x093, 0, 1, 1, 1) | |
3cbc9605 TL |
97 | MUX_CFG_24XX("L3_GPMC_WAIT0", 0x09a, 0, 1, 1, 1) |
98 | MUX_CFG_24XX("N7_GPMC_WAIT1", 0x09b, 0, 1, 1, 1) | |
99 | MUX_CFG_24XX("M1_GPMC_WAIT2", 0x09c, 0, 1, 1, 1) | |
100 | MUX_CFG_24XX("P1_GPMC_WAIT3", 0x09d, 0, 1, 1, 1) | |
101 | ||
8d7f9f50 TL |
102 | /* 24xx McBSP */ |
103 | MUX_CFG_24XX("Y15_24XX_MCBSP2_CLKX", 0x124, 1, 1, 0, 1) | |
104 | MUX_CFG_24XX("R14_24XX_MCBSP2_FSX", 0x125, 1, 1, 0, 1) | |
105 | MUX_CFG_24XX("W15_24XX_MCBSP2_DR", 0x126, 1, 1, 0, 1) | |
106 | MUX_CFG_24XX("V15_24XX_MCBSP2_DX", 0x127, 1, 1, 0, 1) | |
107 | ||
1dbae815 | 108 | /* 24xx GPIO */ |
7d34f3b3 TL |
109 | MUX_CFG_24XX("M21_242X_GPIO11", 0x0c9, 3, 1, 1, 1) |
110 | MUX_CFG_24XX("P21_242X_GPIO12", 0x0ca, 3, 0, 0, 1) | |
111 | MUX_CFG_24XX("AA10_242X_GPIO13", 0x0e5, 3, 0, 0, 1) | |
112 | MUX_CFG_24XX("AA6_242X_GPIO14", 0x0e6, 3, 0, 0, 1) | |
113 | MUX_CFG_24XX("AA4_242X_GPIO15", 0x0e7, 3, 0, 0, 1) | |
114 | MUX_CFG_24XX("Y11_242X_GPIO16", 0x0e8, 3, 0, 0, 1) | |
115 | MUX_CFG_24XX("AA12_242X_GPIO17", 0x0e9, 3, 0, 0, 1) | |
116 | MUX_CFG_24XX("AA8_242X_GPIO58", 0x0ea, 3, 0, 0, 1) | |
1dbae815 | 117 | MUX_CFG_24XX("Y20_24XX_GPIO60", 0x12c, 3, 0, 0, 1) |
7d34f3b3 | 118 | MUX_CFG_24XX("W4__24XX_GPIO74", 0x0f2, 3, 0, 0, 1) |
f7337a19 | 119 | MUX_CFG_24XX("N15_24XX_GPIO85", 0x103, 3, 0, 0, 1) |
1dbae815 | 120 | MUX_CFG_24XX("M15_24XX_GPIO92", 0x10a, 3, 0, 0, 1) |
f7337a19 TL |
121 | MUX_CFG_24XX("P20_24XX_GPIO93", 0x10b, 3, 0, 0, 1) |
122 | MUX_CFG_24XX("P18_24XX_GPIO95", 0x10d, 3, 0, 0, 1) | |
123 | MUX_CFG_24XX("M18_24XX_GPIO96", 0x10e, 3, 0, 0, 1) | |
124 | MUX_CFG_24XX("L14_24XX_GPIO97", 0x10f, 3, 0, 0, 1) | |
7d34f3b3 | 125 | MUX_CFG_24XX("J15_24XX_GPIO99", 0x113, 3, 1, 1, 1) |
8d7f9f50 | 126 | MUX_CFG_24XX("V14_24XX_GPIO117", 0x128, 3, 1, 0, 1) |
7bbb3cc5 | 127 | MUX_CFG_24XX("P14_24XX_GPIO125", 0x140, 3, 1, 1, 1) |
8d7f9f50 | 128 | |
5ac42153 TL |
129 | /* 242x DBG GPIO */ |
130 | MUX_CFG_24XX("V4_242X_GPIO49", 0xd3, 3, 0, 0, 1) | |
131 | MUX_CFG_24XX("W2_242X_GPIO50", 0xd4, 3, 0, 0, 1) | |
132 | MUX_CFG_24XX("U4_242X_GPIO51", 0xd5, 3, 0, 0, 1) | |
133 | MUX_CFG_24XX("V3_242X_GPIO52", 0xd6, 3, 0, 0, 1) | |
134 | MUX_CFG_24XX("V2_242X_GPIO53", 0xd7, 3, 0, 0, 1) | |
135 | MUX_CFG_24XX("V6_242X_GPIO53", 0xcf, 3, 0, 0, 1) | |
136 | MUX_CFG_24XX("T4_242X_GPIO54", 0xd8, 3, 0, 0, 1) | |
137 | MUX_CFG_24XX("Y4_242X_GPIO54", 0xd0, 3, 0, 0, 1) | |
138 | MUX_CFG_24XX("T3_242X_GPIO55", 0xd9, 3, 0, 0, 1) | |
139 | MUX_CFG_24XX("U2_242X_GPIO56", 0xda, 3, 0, 0, 1) | |
140 | ||
141 | /* 24xx external DMA requests */ | |
7d34f3b3 TL |
142 | MUX_CFG_24XX("AA10_242X_DMAREQ0", 0x0e5, 2, 0, 0, 1) |
143 | MUX_CFG_24XX("AA6_242X_DMAREQ1", 0x0e6, 2, 0, 0, 1) | |
144 | MUX_CFG_24XX("E4_242X_DMAREQ2", 0x074, 2, 0, 0, 1) | |
145 | MUX_CFG_24XX("G4_242X_DMAREQ3", 0x073, 2, 0, 0, 1) | |
146 | MUX_CFG_24XX("D3_242X_DMAREQ4", 0x072, 2, 0, 0, 1) | |
147 | MUX_CFG_24XX("E3_242X_DMAREQ5", 0x071, 2, 0, 0, 1) | |
5ac42153 | 148 | |
7d34f3b3 | 149 | /* UART3 */ |
8d7f9f50 TL |
150 | MUX_CFG_24XX("K15_24XX_UART3_TX", 0x118, 0, 0, 0, 1) |
151 | MUX_CFG_24XX("K14_24XX_UART3_RX", 0x119, 0, 0, 0, 1) | |
152 | ||
abc45e1d KP |
153 | /* MMC/SDIO */ |
154 | MUX_CFG_24XX("G19_24XX_MMC_CLKO", 0x0f3, 0, 0, 0, 1) | |
155 | MUX_CFG_24XX("H18_24XX_MMC_CMD", 0x0f4, 0, 0, 0, 1) | |
156 | MUX_CFG_24XX("F20_24XX_MMC_DAT0", 0x0f5, 0, 0, 0, 1) | |
157 | MUX_CFG_24XX("H14_24XX_MMC_DAT1", 0x0f6, 0, 0, 0, 1) | |
158 | MUX_CFG_24XX("E19_24XX_MMC_DAT2", 0x0f7, 0, 0, 0, 1) | |
159 | MUX_CFG_24XX("D19_24XX_MMC_DAT3", 0x0f8, 0, 0, 0, 1) | |
160 | MUX_CFG_24XX("F19_24XX_MMC_DAT_DIR0", 0x0f9, 0, 0, 0, 1) | |
161 | MUX_CFG_24XX("E20_24XX_MMC_DAT_DIR1", 0x0fa, 0, 0, 0, 1) | |
162 | MUX_CFG_24XX("F18_24XX_MMC_DAT_DIR2", 0x0fb, 0, 0, 0, 1) | |
163 | MUX_CFG_24XX("E18_24XX_MMC_DAT_DIR3", 0x0fc, 0, 0, 0, 1) | |
164 | MUX_CFG_24XX("G18_24XX_MMC_CMD_DIR", 0x0fd, 0, 0, 0, 1) | |
165 | MUX_CFG_24XX("H15_24XX_MMC_CLKI", 0x0fe, 0, 0, 0, 1) | |
166 | ||
7bbb3cc5 KP |
167 | /* Full speed USB */ |
168 | MUX_CFG_24XX("J20_24XX_USB0_PUEN", 0x11d, 0, 0, 0, 1) | |
169 | MUX_CFG_24XX("J19_24XX_USB0_VP", 0x11e, 0, 0, 0, 1) | |
170 | MUX_CFG_24XX("K20_24XX_USB0_VM", 0x11f, 0, 0, 0, 1) | |
171 | MUX_CFG_24XX("J18_24XX_USB0_RCV", 0x120, 0, 0, 0, 1) | |
172 | MUX_CFG_24XX("K19_24XX_USB0_TXEN", 0x121, 0, 0, 0, 1) | |
173 | MUX_CFG_24XX("J14_24XX_USB0_SE0", 0x122, 0, 0, 0, 1) | |
174 | MUX_CFG_24XX("K18_24XX_USB0_DAT", 0x123, 0, 0, 0, 1) | |
175 | ||
176 | MUX_CFG_24XX("N14_24XX_USB1_SE0", 0x0ed, 2, 0, 0, 1) | |
177 | MUX_CFG_24XX("W12_24XX_USB1_SE0", 0x0dd, 3, 0, 0, 1) | |
178 | MUX_CFG_24XX("P15_24XX_USB1_DAT", 0x0ee, 2, 0, 0, 1) | |
179 | MUX_CFG_24XX("R13_24XX_USB1_DAT", 0x0e0, 3, 0, 0, 1) | |
180 | MUX_CFG_24XX("W20_24XX_USB1_TXEN", 0x0ec, 2, 0, 0, 1) | |
181 | MUX_CFG_24XX("P13_24XX_USB1_TXEN", 0x0df, 3, 0, 0, 1) | |
182 | MUX_CFG_24XX("V19_24XX_USB1_RCV", 0x0eb, 2, 0, 0, 1) | |
183 | MUX_CFG_24XX("V12_24XX_USB1_RCV", 0x0de, 3, 0, 0, 1) | |
184 | ||
185 | MUX_CFG_24XX("AA10_24XX_USB2_SE0", 0x0e5, 2, 0, 0, 1) | |
186 | MUX_CFG_24XX("Y11_24XX_USB2_DAT", 0x0e8, 2, 0, 0, 1) | |
187 | MUX_CFG_24XX("AA12_24XX_USB2_TXEN", 0x0e9, 2, 0, 0, 1) | |
188 | MUX_CFG_24XX("AA6_24XX_USB2_RCV", 0x0e6, 2, 0, 0, 1) | |
189 | MUX_CFG_24XX("AA4_24XX_USB2_TLLSE0", 0x0e7, 2, 0, 0, 1) | |
190 | ||
8d7f9f50 TL |
191 | /* Keypad GPIO*/ |
192 | MUX_CFG_24XX("T19_24XX_KBR0", 0x106, 3, 1, 1, 1) | |
193 | MUX_CFG_24XX("R19_24XX_KBR1", 0x107, 3, 1, 1, 1) | |
194 | MUX_CFG_24XX("V18_24XX_KBR2", 0x139, 3, 1, 1, 1) | |
195 | MUX_CFG_24XX("M21_24XX_KBR3", 0xc9, 3, 1, 1, 1) | |
196 | MUX_CFG_24XX("E5__24XX_KBR4", 0x138, 3, 1, 1, 1) | |
197 | MUX_CFG_24XX("M18_24XX_KBR5", 0x10e, 3, 1, 1, 1) | |
198 | MUX_CFG_24XX("R20_24XX_KBC0", 0x108, 3, 0, 0, 1) | |
199 | MUX_CFG_24XX("M14_24XX_KBC1", 0x109, 3, 0, 0, 1) | |
200 | MUX_CFG_24XX("H19_24XX_KBC2", 0x114, 3, 0, 0, 1) | |
201 | MUX_CFG_24XX("V17_24XX_KBC3", 0x135, 3, 0, 0, 1) | |
202 | MUX_CFG_24XX("P21_24XX_KBC4", 0xca, 3, 0, 0, 1) | |
203 | MUX_CFG_24XX("L14_24XX_KBC5", 0x10f, 3, 0, 0, 1) | |
204 | MUX_CFG_24XX("N19_24XX_KBC6", 0x110, 3, 0, 0, 1) | |
205 | ||
206 | /* 24xx Menelaus Keypad GPIO */ | |
207 | MUX_CFG_24XX("B3__24XX_KBR5", 0x30, 3, 1, 1, 1) | |
208 | MUX_CFG_24XX("AA4_24XX_KBC2", 0xe7, 3, 0, 0, 1) | |
209 | MUX_CFG_24XX("B13_24XX_KBC6", 0x110, 3, 0, 0, 1) | |
1dbae815 | 210 | |
f7337a19 TL |
211 | /* 2430 USB */ |
212 | MUX_CFG_24XX("AD9_2430_USB0_PUEN", 0x133, 4, 0, 0, 1) | |
213 | MUX_CFG_24XX("Y11_2430_USB0_VP", 0x134, 4, 0, 0, 1) | |
214 | MUX_CFG_24XX("AD7_2430_USB0_VM", 0x135, 4, 0, 0, 1) | |
215 | MUX_CFG_24XX("AE7_2430_USB0_RCV", 0x136, 4, 0, 0, 1) | |
216 | MUX_CFG_24XX("AD4_2430_USB0_TXEN", 0x137, 4, 0, 0, 1) | |
217 | MUX_CFG_24XX("AF9_2430_USB0_SE0", 0x138, 4, 0, 0, 1) | |
218 | MUX_CFG_24XX("AE6_2430_USB0_DAT", 0x139, 4, 0, 0, 1) | |
219 | MUX_CFG_24XX("AD24_2430_USB1_SE0", 0x107, 2, 0, 0, 1) | |
220 | MUX_CFG_24XX("AB24_2430_USB1_RCV", 0x108, 2, 0, 0, 1) | |
221 | MUX_CFG_24XX("Y25_2430_USB1_TXEN", 0x109, 2, 0, 0, 1) | |
222 | MUX_CFG_24XX("AA26_2430_USB1_DAT", 0x10A, 2, 0, 0, 1) | |
223 | ||
224 | /* 2430 HS-USB */ | |
225 | MUX_CFG_24XX("AD9_2430_USB0HS_DATA3", 0x133, 0, 0, 0, 1) | |
226 | MUX_CFG_24XX("Y11_2430_USB0HS_DATA4", 0x134, 0, 0, 0, 1) | |
227 | MUX_CFG_24XX("AD7_2430_USB0HS_DATA5", 0x135, 0, 0, 0, 1) | |
228 | MUX_CFG_24XX("AE7_2430_USB0HS_DATA6", 0x136, 0, 0, 0, 1) | |
229 | MUX_CFG_24XX("AD4_2430_USB0HS_DATA2", 0x137, 0, 0, 0, 1) | |
230 | MUX_CFG_24XX("AF9_2430_USB0HS_DATA0", 0x138, 0, 0, 0, 1) | |
231 | MUX_CFG_24XX("AE6_2430_USB0HS_DATA1", 0x139, 0, 0, 0, 1) | |
232 | MUX_CFG_24XX("AE8_2430_USB0HS_CLK", 0x13A, 0, 0, 0, 1) | |
233 | MUX_CFG_24XX("AD8_2430_USB0HS_DIR", 0x13B, 0, 0, 0, 1) | |
234 | MUX_CFG_24XX("AE5_2430_USB0HS_STP", 0x13c, 0, 1, 1, 1) | |
235 | MUX_CFG_24XX("AE9_2430_USB0HS_NXT", 0x13D, 0, 0, 0, 1) | |
236 | MUX_CFG_24XX("AC7_2430_USB0HS_DATA7", 0x13E, 0, 0, 0, 1) | |
237 | ||
238 | /* 2430 McBSP */ | |
2619bc32 AK |
239 | MUX_CFG_24XX("AD6_2430_MCBSP_CLKS", 0x011E, 0, 0, 0, 1) |
240 | ||
241 | MUX_CFG_24XX("AB2_2430_MCBSP1_CLKR", 0x011A, 0, 0, 0, 1) | |
242 | MUX_CFG_24XX("AD5_2430_MCBSP1_FSR", 0x011B, 0, 0, 0, 1) | |
243 | MUX_CFG_24XX("AA1_2430_MCBSP1_DX", 0x011C, 0, 0, 0, 1) | |
244 | MUX_CFG_24XX("AF3_2430_MCBSP1_DR", 0x011D, 0, 0, 0, 1) | |
245 | MUX_CFG_24XX("AB3_2430_MCBSP1_FSX", 0x011F, 0, 0, 0, 1) | |
246 | MUX_CFG_24XX("Y9_2430_MCBSP1_CLKX", 0x0120, 0, 0, 0, 1) | |
247 | ||
f7337a19 TL |
248 | MUX_CFG_24XX("AC10_2430_MCBSP2_FSX", 0x012E, 1, 0, 0, 1) |
249 | MUX_CFG_24XX("AD16_2430_MCBSP2_CLX", 0x012F, 1, 0, 0, 1) | |
250 | MUX_CFG_24XX("AE13_2430_MCBSP2_DX", 0x0130, 1, 0, 0, 1) | |
251 | MUX_CFG_24XX("AD13_2430_MCBSP2_DR", 0x0131, 1, 0, 0, 1) | |
252 | MUX_CFG_24XX("AC10_2430_MCBSP2_FSX_OFF",0x012E, 0, 0, 0, 1) | |
253 | MUX_CFG_24XX("AD16_2430_MCBSP2_CLX_OFF",0x012F, 0, 0, 0, 1) | |
254 | MUX_CFG_24XX("AE13_2430_MCBSP2_DX_OFF", 0x0130, 0, 0, 0, 1) | |
255 | MUX_CFG_24XX("AD13_2430_MCBSP2_DR_OFF", 0x0131, 0, 0, 0, 1) | |
2619bc32 AK |
256 | |
257 | MUX_CFG_24XX("AC9_2430_MCBSP3_CLKX", 0x0103, 0, 0, 0, 1) | |
258 | MUX_CFG_24XX("AE4_2430_MCBSP3_FSX", 0x0104, 0, 0, 0, 1) | |
259 | MUX_CFG_24XX("AE2_2430_MCBSP3_DR", 0x0105, 0, 0, 0, 1) | |
260 | MUX_CFG_24XX("AF4_2430_MCBSP3_DX", 0x0106, 0, 0, 0, 1) | |
261 | ||
262 | MUX_CFG_24XX("N3_2430_MCBSP4_CLKX", 0x010B, 1, 0, 0, 1) | |
263 | MUX_CFG_24XX("AD23_2430_MCBSP4_DR", 0x010C, 1, 0, 0, 1) | |
264 | MUX_CFG_24XX("AB25_2430_MCBSP4_DX", 0x010D, 1, 0, 0, 1) | |
265 | MUX_CFG_24XX("AC25_2430_MCBSP4_FSX", 0x010E, 1, 0, 0, 1) | |
266 | ||
267 | MUX_CFG_24XX("AE16_2430_MCBSP5_CLKX", 0x00ED, 1, 0, 0, 1) | |
268 | MUX_CFG_24XX("AF12_2430_MCBSP5_FSX", 0x00ED, 1, 0, 0, 1) | |
269 | MUX_CFG_24XX("K7_2430_MCBSP5_DX", 0x00EF, 1, 0, 0, 1) | |
270 | MUX_CFG_24XX("M1_2430_MCBSP5_DR", 0x00F0, 1, 0, 0, 1) | |
271 | ||
272 | /* 2430 MCSPI1 */ | |
273 | MUX_CFG_24XX("Y18_2430_MCSPI1_CLK", 0x010F, 0, 0, 0, 1) | |
274 | MUX_CFG_24XX("AD15_2430_MCSPI1_SIMO", 0x0110, 0, 0, 0, 1) | |
275 | MUX_CFG_24XX("AE17_2430_MCSPI1_SOMI", 0x0111, 0, 0, 0, 1) | |
276 | MUX_CFG_24XX("U1_2430_MCSPI1_CS0", 0x0112, 0, 0, 0, 1) | |
277 | ||
278 | /* Touchscreen GPIO */ | |
279 | MUX_CFG_24XX("AF19_2430_GPIO_85", 0x0113, 3, 0, 0, 1) | |
280 | ||
1dbae815 TL |
281 | }; |
282 | ||
9330899e TL |
283 | #define OMAP24XX_PINS_SZ ARRAY_SIZE(omap24xx_pins) |
284 | ||
9330899e | 285 | #if defined(CONFIG_OMAP_MUX_DEBUG) || defined(CONFIG_OMAP_MUX_WARNINGS) |
15f45e6f | 286 | |
2351872c | 287 | static void __init_or_module omap2_cfg_debug(const struct pin_config *cfg, u16 reg) |
9330899e TL |
288 | { |
289 | u16 orig; | |
290 | u8 warn = 0, debug = 0; | |
291 | ||
92c9f501 | 292 | orig = omap_mux_read(cfg->mux_reg - OMAP_MUX_BASE_OFFSET); |
9330899e TL |
293 | |
294 | #ifdef CONFIG_OMAP_MUX_DEBUG | |
295 | debug = cfg->debug; | |
296 | #endif | |
297 | warn = (orig != reg); | |
298 | if (debug || warn) | |
299 | printk(KERN_WARNING | |
a58caad1 | 300 | "MUX: setup %s (0x%p): 0x%04x -> 0x%04x\n", |
44595982 PW |
301 | cfg->name, omap_ctrl_base_get() + cfg->mux_reg, |
302 | orig, reg); | |
9330899e TL |
303 | } |
304 | #else | |
305 | #define omap2_cfg_debug(x, y) do {} while (0) | |
306 | #endif | |
307 | ||
2619bc32 | 308 | static int __init_or_module omap24xx_cfg_reg(const struct pin_config *cfg) |
1dbae815 | 309 | { |
9330899e TL |
310 | static DEFINE_SPINLOCK(mux_spin_lock); |
311 | unsigned long flags; | |
225dfda1 | 312 | u8 reg = 0; |
225dfda1 | 313 | |
9330899e | 314 | spin_lock_irqsave(&mux_spin_lock, flags); |
225dfda1 TL |
315 | reg |= cfg->mask & 0x7; |
316 | if (cfg->pull_val) | |
2351872c | 317 | reg |= OMAP2_PULL_ENA; |
9330899e | 318 | if (cfg->pu_pd_val) |
2351872c | 319 | reg |= OMAP2_PULL_UP; |
9330899e | 320 | omap2_cfg_debug(cfg, reg); |
92c9f501 | 321 | omap_mux_write(reg, cfg->mux_reg - OMAP_MUX_BASE_OFFSET); |
9330899e | 322 | spin_unlock_irqrestore(&mux_spin_lock, flags); |
225dfda1 | 323 | |
1dbae815 TL |
324 | return 0; |
325 | } | |
7d7f665d TL |
326 | |
327 | int __init omap2_mux_init(void) | |
328 | { | |
92c9f501 MR |
329 | u32 mux_pbase; |
330 | ||
331 | if (cpu_is_omap2420()) | |
332 | mux_pbase = OMAP2420_CTRL_BASE + OMAP_MUX_BASE_OFFSET; | |
333 | else if (cpu_is_omap2430()) | |
334 | mux_pbase = OMAP243X_CTRL_BASE + OMAP_MUX_BASE_OFFSET; | |
15ac7afe TL |
335 | else |
336 | return -ENODEV; | |
92c9f501 MR |
337 | |
338 | mux_base = ioremap(mux_pbase, OMAP_MUX_BASE_SZ); | |
339 | if (!mux_base) { | |
340 | printk(KERN_ERR "mux: Could not ioremap\n"); | |
341 | return -ENODEV; | |
342 | } | |
343 | ||
7d7f665d TL |
344 | if (cpu_is_omap24xx()) { |
345 | arch_mux_cfg.pins = omap24xx_pins; | |
9330899e | 346 | arch_mux_cfg.size = OMAP24XX_PINS_SZ; |
7d7f665d | 347 | arch_mux_cfg.cfg_reg = omap24xx_cfg_reg; |
15f45e6f TL |
348 | |
349 | return omap_mux_register(&arch_mux_cfg); | |
7d7f665d | 350 | } |
7d7f665d | 351 | |
15f45e6f | 352 | return 0; |
7d7f665d | 353 | } |
1dbae815 | 354 | |
15f45e6f TL |
355 | #else |
356 | int __init omap2_mux_init(void) | |
357 | { | |
358 | return 0; | |
359 | } | |
15ac7afe TL |
360 | #endif /* CONFIG_OMAP_MUX */ |
361 | ||
362 | /*----------------------------------------------------------------------------*/ | |
363 | ||
364 | #ifdef CONFIG_ARCH_OMAP34XX | |
15ac7afe TL |
365 | static LIST_HEAD(muxmodes); |
366 | static DEFINE_MUTEX(muxmode_mutex); | |
367 | ||
368 | #ifdef CONFIG_OMAP_MUX | |
369 | ||
370 | static char *omap_mux_options; | |
371 | ||
372 | int __init omap_mux_init_gpio(int gpio, int val) | |
373 | { | |
374 | struct omap_mux_entry *e; | |
375 | int found = 0; | |
376 | ||
377 | if (!gpio) | |
378 | return -EINVAL; | |
379 | ||
380 | list_for_each_entry(e, &muxmodes, node) { | |
381 | struct omap_mux *m = &e->mux; | |
382 | if (gpio == m->gpio) { | |
383 | u16 old_mode; | |
384 | u16 mux_mode; | |
385 | ||
386 | old_mode = omap_mux_read(m->reg_offset); | |
387 | mux_mode = val & ~(OMAP_MUX_NR_MODES - 1); | |
388 | mux_mode |= OMAP_MUX_MODE4; | |
389 | printk(KERN_DEBUG "mux: Setting signal " | |
390 | "%s.gpio%i 0x%04x -> 0x%04x\n", | |
391 | m->muxnames[0], gpio, old_mode, mux_mode); | |
392 | omap_mux_write(mux_mode, m->reg_offset); | |
393 | found++; | |
394 | } | |
395 | } | |
396 | ||
397 | if (found == 1) | |
398 | return 0; | |
399 | ||
400 | if (found > 1) { | |
401 | printk(KERN_ERR "mux: Multiple gpio paths for gpio%i\n", gpio); | |
402 | return -EINVAL; | |
403 | } | |
404 | ||
405 | printk(KERN_ERR "mux: Could not set gpio%i\n", gpio); | |
406 | ||
407 | return -ENODEV; | |
408 | } | |
409 | ||
410 | int __init omap_mux_init_signal(char *muxname, int val) | |
411 | { | |
412 | struct omap_mux_entry *e; | |
413 | char *m0_name = NULL, *mode_name = NULL; | |
414 | int found = 0; | |
415 | ||
416 | mode_name = strchr(muxname, '.'); | |
417 | if (mode_name) { | |
418 | *mode_name = '\0'; | |
419 | mode_name++; | |
420 | m0_name = muxname; | |
421 | } else { | |
422 | mode_name = muxname; | |
423 | } | |
424 | ||
425 | list_for_each_entry(e, &muxmodes, node) { | |
426 | struct omap_mux *m = &e->mux; | |
427 | char *m0_entry = m->muxnames[0]; | |
428 | int i; | |
429 | ||
430 | if (m0_name && strcmp(m0_name, m0_entry)) | |
431 | continue; | |
432 | ||
433 | for (i = 0; i < OMAP_MUX_NR_MODES; i++) { | |
434 | char *mode_cur = m->muxnames[i]; | |
435 | ||
436 | if (!mode_cur) | |
437 | continue; | |
438 | ||
439 | if (!strcmp(mode_name, mode_cur)) { | |
440 | u16 old_mode; | |
441 | u16 mux_mode; | |
442 | ||
443 | old_mode = omap_mux_read(m->reg_offset); | |
444 | mux_mode = val | i; | |
445 | printk(KERN_DEBUG "mux: Setting signal " | |
446 | "%s.%s 0x%04x -> 0x%04x\n", | |
447 | m0_entry, muxname, old_mode, mux_mode); | |
448 | omap_mux_write(mux_mode, m->reg_offset); | |
449 | found++; | |
450 | } | |
451 | } | |
452 | } | |
453 | ||
454 | if (found == 1) | |
455 | return 0; | |
456 | ||
457 | if (found > 1) { | |
458 | printk(KERN_ERR "mux: Multiple signal paths (%i) for %s\n", | |
459 | found, muxname); | |
460 | return -EINVAL; | |
461 | } | |
462 | ||
463 | printk(KERN_ERR "mux: Could not set signal %s\n", muxname); | |
464 | ||
465 | return -ENODEV; | |
466 | } | |
467 | ||
4b715efc TL |
468 | #ifdef CONFIG_DEBUG_FS |
469 | ||
470 | #define OMAP_MUX_MAX_NR_FLAGS 10 | |
471 | #define OMAP_MUX_TEST_FLAG(val, mask) \ | |
472 | if (((val) & (mask)) == (mask)) { \ | |
473 | i++; \ | |
474 | flags[i] = #mask; \ | |
475 | } | |
476 | ||
477 | /* REVISIT: Add checking for non-optimal mux settings */ | |
478 | static inline void omap_mux_decode(struct seq_file *s, u16 val) | |
479 | { | |
480 | char *flags[OMAP_MUX_MAX_NR_FLAGS]; | |
481 | char mode[14]; | |
482 | int i = -1; | |
483 | ||
484 | sprintf(mode, "OMAP_MUX_MODE%d", val & 0x7); | |
485 | i++; | |
486 | flags[i] = mode; | |
487 | ||
488 | OMAP_MUX_TEST_FLAG(val, OMAP_PIN_OFF_WAKEUPENABLE); | |
489 | if (val & OMAP_OFF_EN) { | |
490 | if (!(val & OMAP_OFFOUT_EN)) { | |
491 | if (!(val & OMAP_OFF_PULL_UP)) { | |
492 | OMAP_MUX_TEST_FLAG(val, | |
493 | OMAP_PIN_OFF_INPUT_PULLDOWN); | |
494 | } else { | |
495 | OMAP_MUX_TEST_FLAG(val, | |
496 | OMAP_PIN_OFF_INPUT_PULLUP); | |
497 | } | |
498 | } else { | |
499 | if (!(val & OMAP_OFFOUT_VAL)) { | |
500 | OMAP_MUX_TEST_FLAG(val, | |
501 | OMAP_PIN_OFF_OUTPUT_LOW); | |
502 | } else { | |
503 | OMAP_MUX_TEST_FLAG(val, | |
504 | OMAP_PIN_OFF_OUTPUT_HIGH); | |
505 | } | |
506 | } | |
507 | } | |
508 | ||
509 | if (val & OMAP_INPUT_EN) { | |
510 | if (val & OMAP_PULL_ENA) { | |
511 | if (!(val & OMAP_PULL_UP)) { | |
512 | OMAP_MUX_TEST_FLAG(val, | |
513 | OMAP_PIN_INPUT_PULLDOWN); | |
514 | } else { | |
515 | OMAP_MUX_TEST_FLAG(val, OMAP_PIN_INPUT_PULLUP); | |
516 | } | |
517 | } else { | |
518 | OMAP_MUX_TEST_FLAG(val, OMAP_PIN_INPUT); | |
519 | } | |
520 | } else { | |
521 | i++; | |
522 | flags[i] = "OMAP_PIN_OUTPUT"; | |
523 | } | |
524 | ||
525 | do { | |
526 | seq_printf(s, "%s", flags[i]); | |
527 | if (i > 0) | |
528 | seq_printf(s, " | "); | |
529 | } while (i-- > 0); | |
530 | } | |
531 | ||
532 | #define OMAP_MUX_DEFNAME_LEN 16 | |
533 | ||
534 | static int omap_mux_dbg_board_show(struct seq_file *s, void *unused) | |
535 | { | |
536 | struct omap_mux_entry *e; | |
537 | ||
538 | list_for_each_entry(e, &muxmodes, node) { | |
539 | struct omap_mux *m = &e->mux; | |
540 | char m0_def[OMAP_MUX_DEFNAME_LEN]; | |
541 | char *m0_name = m->muxnames[0]; | |
542 | u16 val; | |
543 | int i, mode; | |
544 | ||
545 | if (!m0_name) | |
546 | continue; | |
547 | ||
548 | for (i = 0; i < OMAP_MUX_DEFNAME_LEN; i++) { | |
549 | if (m0_name[i] == '\0') { | |
550 | m0_def[i] = m0_name[i]; | |
551 | break; | |
552 | } | |
553 | m0_def[i] = toupper(m0_name[i]); | |
554 | } | |
555 | val = omap_mux_read(m->reg_offset); | |
556 | mode = val & OMAP_MUX_MODE7; | |
557 | ||
558 | seq_printf(s, "OMAP%i_MUX(%s, ", | |
559 | cpu_is_omap34xx() ? 3 : 0, m0_def); | |
560 | omap_mux_decode(s, val); | |
561 | seq_printf(s, "),\n"); | |
562 | } | |
563 | ||
564 | return 0; | |
565 | } | |
566 | ||
567 | static int omap_mux_dbg_board_open(struct inode *inode, struct file *file) | |
568 | { | |
569 | return single_open(file, omap_mux_dbg_board_show, &inode->i_private); | |
570 | } | |
571 | ||
572 | static const struct file_operations omap_mux_dbg_board_fops = { | |
573 | .open = omap_mux_dbg_board_open, | |
574 | .read = seq_read, | |
575 | .llseek = seq_lseek, | |
576 | .release = single_release, | |
577 | }; | |
578 | ||
579 | static int omap_mux_dbg_signal_show(struct seq_file *s, void *unused) | |
580 | { | |
581 | struct omap_mux *m = s->private; | |
582 | const char *none = "NA"; | |
583 | u16 val; | |
584 | int mode; | |
585 | ||
586 | val = omap_mux_read(m->reg_offset); | |
587 | mode = val & OMAP_MUX_MODE7; | |
588 | ||
589 | seq_printf(s, "name: %s.%s (0x%08lx/0x%03x = 0x%04x), b %s, t %s\n", | |
590 | m->muxnames[0], m->muxnames[mode], | |
591 | mux_phys + m->reg_offset, m->reg_offset, val, | |
592 | m->balls[0] ? m->balls[0] : none, | |
593 | m->balls[1] ? m->balls[1] : none); | |
594 | seq_printf(s, "mode: "); | |
595 | omap_mux_decode(s, val); | |
596 | seq_printf(s, "\n"); | |
597 | seq_printf(s, "signals: %s | %s | %s | %s | %s | %s | %s | %s\n", | |
598 | m->muxnames[0] ? m->muxnames[0] : none, | |
599 | m->muxnames[1] ? m->muxnames[1] : none, | |
600 | m->muxnames[2] ? m->muxnames[2] : none, | |
601 | m->muxnames[3] ? m->muxnames[3] : none, | |
602 | m->muxnames[4] ? m->muxnames[4] : none, | |
603 | m->muxnames[5] ? m->muxnames[5] : none, | |
604 | m->muxnames[6] ? m->muxnames[6] : none, | |
605 | m->muxnames[7] ? m->muxnames[7] : none); | |
606 | ||
607 | return 0; | |
608 | } | |
609 | ||
610 | #define OMAP_MUX_MAX_ARG_CHAR 7 | |
611 | ||
612 | static ssize_t omap_mux_dbg_signal_write(struct file *file, | |
613 | const char __user *user_buf, | |
614 | size_t count, loff_t *ppos) | |
615 | { | |
616 | char buf[OMAP_MUX_MAX_ARG_CHAR]; | |
617 | struct seq_file *seqf; | |
618 | struct omap_mux *m; | |
619 | unsigned long val; | |
620 | int buf_size, ret; | |
621 | ||
622 | if (count > OMAP_MUX_MAX_ARG_CHAR) | |
623 | return -EINVAL; | |
624 | ||
625 | memset(buf, 0, sizeof(buf)); | |
626 | buf_size = min(count, sizeof(buf) - 1); | |
627 | ||
628 | if (copy_from_user(buf, user_buf, buf_size)) | |
629 | return -EFAULT; | |
630 | ||
631 | ret = strict_strtoul(buf, 0x10, &val); | |
632 | if (ret < 0) | |
633 | return ret; | |
634 | ||
635 | if (val > 0xffff) | |
636 | return -EINVAL; | |
637 | ||
638 | seqf = file->private_data; | |
639 | m = seqf->private; | |
640 | ||
641 | omap_mux_write((u16)val, m->reg_offset); | |
642 | *ppos += count; | |
643 | ||
644 | return count; | |
645 | } | |
646 | ||
647 | static int omap_mux_dbg_signal_open(struct inode *inode, struct file *file) | |
648 | { | |
649 | return single_open(file, omap_mux_dbg_signal_show, inode->i_private); | |
650 | } | |
651 | ||
652 | static const struct file_operations omap_mux_dbg_signal_fops = { | |
653 | .open = omap_mux_dbg_signal_open, | |
654 | .read = seq_read, | |
655 | .write = omap_mux_dbg_signal_write, | |
656 | .llseek = seq_lseek, | |
657 | .release = single_release, | |
658 | }; | |
659 | ||
660 | static struct dentry *mux_dbg_dir; | |
661 | ||
662 | static void __init omap_mux_dbg_init(void) | |
663 | { | |
664 | struct omap_mux_entry *e; | |
665 | ||
666 | mux_dbg_dir = debugfs_create_dir("omap_mux", NULL); | |
667 | if (!mux_dbg_dir) | |
668 | return; | |
669 | ||
670 | (void)debugfs_create_file("board", S_IRUGO, mux_dbg_dir, | |
671 | NULL, &omap_mux_dbg_board_fops); | |
672 | ||
673 | list_for_each_entry(e, &muxmodes, node) { | |
674 | struct omap_mux *m = &e->mux; | |
675 | ||
676 | (void)debugfs_create_file(m->muxnames[0], S_IWUGO, mux_dbg_dir, | |
677 | m, &omap_mux_dbg_signal_fops); | |
678 | } | |
679 | } | |
680 | ||
681 | #else | |
682 | static inline void omap_mux_dbg_init(void) | |
683 | { | |
684 | } | |
685 | #endif /* CONFIG_DEBUG_FS */ | |
686 | ||
15ac7afe TL |
687 | static void __init omap_mux_free_names(struct omap_mux *m) |
688 | { | |
689 | int i; | |
690 | ||
691 | for (i = 0; i < OMAP_MUX_NR_MODES; i++) | |
692 | kfree(m->muxnames[i]); | |
693 | ||
694 | #ifdef CONFIG_DEBUG_FS | |
695 | for (i = 0; i < OMAP_MUX_NR_SIDES; i++) | |
696 | kfree(m->balls[i]); | |
697 | #endif | |
698 | ||
699 | } | |
700 | ||
701 | /* Free all data except for GPIO pins unless CONFIG_DEBUG_FS is set */ | |
702 | static int __init omap_mux_late_init(void) | |
703 | { | |
704 | struct omap_mux_entry *e, *tmp; | |
705 | ||
706 | list_for_each_entry_safe(e, tmp, &muxmodes, node) { | |
707 | struct omap_mux *m = &e->mux; | |
708 | u16 mode = omap_mux_read(m->reg_offset); | |
709 | ||
710 | if (OMAP_MODE_GPIO(mode)) | |
711 | continue; | |
712 | ||
713 | #ifndef CONFIG_DEBUG_FS | |
714 | mutex_lock(&muxmode_mutex); | |
715 | list_del(&e->node); | |
716 | mutex_unlock(&muxmode_mutex); | |
717 | omap_mux_free_names(m); | |
718 | kfree(m); | |
1dbae815 | 719 | #endif |
15ac7afe TL |
720 | |
721 | } | |
722 | ||
4b715efc TL |
723 | omap_mux_dbg_init(); |
724 | ||
15ac7afe TL |
725 | return 0; |
726 | } | |
727 | late_initcall(omap_mux_late_init); | |
728 | ||
729 | static void __init omap_mux_package_fixup(struct omap_mux *p, | |
730 | struct omap_mux *superset) | |
731 | { | |
732 | while (p->reg_offset != OMAP_MUX_TERMINATOR) { | |
733 | struct omap_mux *s = superset; | |
734 | int found = 0; | |
735 | ||
736 | while (s->reg_offset != OMAP_MUX_TERMINATOR) { | |
737 | if (s->reg_offset == p->reg_offset) { | |
738 | *s = *p; | |
739 | found++; | |
740 | break; | |
741 | } | |
742 | s++; | |
743 | } | |
744 | if (!found) | |
745 | printk(KERN_ERR "mux: Unknown entry offset 0x%x\n", | |
746 | p->reg_offset); | |
747 | p++; | |
748 | } | |
749 | } | |
750 | ||
751 | #ifdef CONFIG_DEBUG_FS | |
752 | ||
753 | static void __init omap_mux_package_init_balls(struct omap_ball *b, | |
754 | struct omap_mux *superset) | |
755 | { | |
756 | while (b->reg_offset != OMAP_MUX_TERMINATOR) { | |
757 | struct omap_mux *s = superset; | |
758 | int found = 0; | |
759 | ||
760 | while (s->reg_offset != OMAP_MUX_TERMINATOR) { | |
761 | if (s->reg_offset == b->reg_offset) { | |
762 | s->balls[0] = b->balls[0]; | |
763 | s->balls[1] = b->balls[1]; | |
764 | found++; | |
765 | break; | |
766 | } | |
767 | s++; | |
768 | } | |
769 | if (!found) | |
770 | printk(KERN_ERR "mux: Unknown ball offset 0x%x\n", | |
771 | b->reg_offset); | |
772 | b++; | |
773 | } | |
774 | } | |
775 | ||
776 | #else /* CONFIG_DEBUG_FS */ | |
777 | ||
778 | static inline void omap_mux_package_init_balls(struct omap_ball *b, | |
779 | struct omap_mux *superset) | |
780 | { | |
781 | } | |
782 | ||
783 | #endif /* CONFIG_DEBUG_FS */ | |
784 | ||
785 | static int __init omap_mux_setup(char *options) | |
786 | { | |
787 | if (!options) | |
788 | return 0; | |
789 | ||
790 | omap_mux_options = options; | |
791 | ||
792 | return 1; | |
793 | } | |
794 | __setup("omap_mux=", omap_mux_setup); | |
795 | ||
796 | /* | |
797 | * Note that the omap_mux=some.signal1=0x1234,some.signal2=0x1234 | |
798 | * cmdline options only override the bootloader values. | |
799 | * During development, please enable CONFIG_DEBUG_FS, and use the | |
800 | * signal specific entries under debugfs. | |
801 | */ | |
802 | static void __init omap_mux_set_cmdline_signals(void) | |
803 | { | |
804 | char *options, *next_opt, *token; | |
805 | ||
806 | if (!omap_mux_options) | |
807 | return; | |
808 | ||
809 | options = kmalloc(strlen(omap_mux_options) + 1, GFP_KERNEL); | |
810 | if (!options) | |
811 | return; | |
812 | ||
813 | strcpy(options, omap_mux_options); | |
814 | next_opt = options; | |
815 | ||
816 | while ((token = strsep(&next_opt, ",")) != NULL) { | |
817 | char *keyval, *name; | |
818 | unsigned long val; | |
819 | ||
820 | keyval = token; | |
821 | name = strsep(&keyval, "="); | |
822 | if (name) { | |
823 | int res; | |
824 | ||
825 | res = strict_strtoul(keyval, 0x10, &val); | |
826 | if (res < 0) | |
827 | continue; | |
828 | ||
829 | omap_mux_init_signal(name, (u16)val); | |
830 | } | |
831 | } | |
832 | ||
833 | kfree(options); | |
834 | } | |
835 | ||
836 | static void __init omap_mux_set_board_signals(struct omap_board_mux *board_mux) | |
837 | { | |
838 | while (board_mux->reg_offset != OMAP_MUX_TERMINATOR) { | |
839 | omap_mux_write(board_mux->value, board_mux->reg_offset); | |
840 | board_mux++; | |
841 | } | |
842 | } | |
843 | ||
844 | static int __init omap_mux_copy_names(struct omap_mux *src, | |
845 | struct omap_mux *dst) | |
846 | { | |
847 | int i; | |
848 | ||
849 | for (i = 0; i < OMAP_MUX_NR_MODES; i++) { | |
850 | if (src->muxnames[i]) { | |
851 | dst->muxnames[i] = | |
852 | kmalloc(strlen(src->muxnames[i]) + 1, | |
853 | GFP_KERNEL); | |
854 | if (!dst->muxnames[i]) | |
855 | goto free; | |
856 | strcpy(dst->muxnames[i], src->muxnames[i]); | |
857 | } | |
858 | } | |
859 | ||
860 | #ifdef CONFIG_DEBUG_FS | |
861 | for (i = 0; i < OMAP_MUX_NR_SIDES; i++) { | |
862 | if (src->balls[i]) { | |
863 | dst->balls[i] = | |
864 | kmalloc(strlen(src->balls[i]) + 1, | |
865 | GFP_KERNEL); | |
866 | if (!dst->balls[i]) | |
867 | goto free; | |
868 | strcpy(dst->balls[i], src->balls[i]); | |
869 | } | |
870 | } | |
871 | #endif | |
872 | ||
873 | return 0; | |
874 | ||
875 | free: | |
876 | omap_mux_free_names(dst); | |
877 | return -ENOMEM; | |
878 | ||
879 | } | |
880 | ||
881 | #endif /* CONFIG_OMAP_MUX */ | |
882 | ||
883 | static u16 omap_mux_get_by_gpio(int gpio) | |
884 | { | |
885 | struct omap_mux_entry *e; | |
886 | u16 offset = OMAP_MUX_TERMINATOR; | |
887 | ||
888 | list_for_each_entry(e, &muxmodes, node) { | |
889 | struct omap_mux *m = &e->mux; | |
890 | if (m->gpio == gpio) { | |
891 | offset = m->reg_offset; | |
892 | break; | |
893 | } | |
894 | } | |
895 | ||
896 | return offset; | |
897 | } | |
898 | ||
899 | /* Needed for dynamic muxing of GPIO pins for off-idle */ | |
900 | u16 omap_mux_get_gpio(int gpio) | |
901 | { | |
902 | u16 offset; | |
903 | ||
904 | offset = omap_mux_get_by_gpio(gpio); | |
905 | if (offset == OMAP_MUX_TERMINATOR) { | |
906 | printk(KERN_ERR "mux: Could not get gpio%i\n", gpio); | |
907 | return offset; | |
908 | } | |
909 | ||
910 | return omap_mux_read(offset); | |
911 | } | |
912 | ||
913 | /* Needed for dynamic muxing of GPIO pins for off-idle */ | |
914 | void omap_mux_set_gpio(u16 val, int gpio) | |
915 | { | |
916 | u16 offset; | |
917 | ||
918 | offset = omap_mux_get_by_gpio(gpio); | |
919 | if (offset == OMAP_MUX_TERMINATOR) { | |
920 | printk(KERN_ERR "mux: Could not set gpio%i\n", gpio); | |
921 | return; | |
922 | } | |
923 | ||
924 | omap_mux_write(val, offset); | |
925 | } | |
926 | ||
927 | static struct omap_mux * __init omap_mux_list_add(struct omap_mux *src) | |
928 | { | |
929 | struct omap_mux_entry *entry; | |
930 | struct omap_mux *m; | |
931 | ||
932 | entry = kzalloc(sizeof(struct omap_mux_entry), GFP_KERNEL); | |
933 | if (!entry) | |
934 | return NULL; | |
935 | ||
936 | m = &entry->mux; | |
937 | memcpy(m, src, sizeof(struct omap_mux_entry)); | |
938 | ||
939 | #ifdef CONFIG_OMAP_MUX | |
940 | if (omap_mux_copy_names(src, m)) { | |
941 | kfree(entry); | |
942 | return NULL; | |
943 | } | |
944 | #endif | |
945 | ||
946 | mutex_lock(&muxmode_mutex); | |
947 | list_add_tail(&entry->node, &muxmodes); | |
948 | mutex_unlock(&muxmode_mutex); | |
949 | ||
950 | return m; | |
951 | } | |
952 | ||
953 | /* | |
954 | * Note if CONFIG_OMAP_MUX is not selected, we will only initialize | |
955 | * the GPIO to mux offset mapping that is needed for dynamic muxing | |
956 | * of GPIO pins for off-idle. | |
957 | */ | |
958 | static void __init omap_mux_init_list(struct omap_mux *superset) | |
959 | { | |
960 | while (superset->reg_offset != OMAP_MUX_TERMINATOR) { | |
961 | struct omap_mux *entry; | |
962 | ||
963 | #ifndef CONFIG_OMAP_MUX | |
964 | /* Skip pins that are not muxed as GPIO by bootloader */ | |
965 | if (!OMAP_MODE_GPIO(omap_mux_read(superset->reg_offset))) { | |
966 | superset++; | |
967 | continue; | |
968 | } | |
969 | #endif | |
970 | ||
971 | entry = omap_mux_list_add(superset); | |
972 | if (!entry) { | |
973 | printk(KERN_ERR "mux: Could not add entry\n"); | |
974 | return; | |
975 | } | |
976 | superset++; | |
977 | } | |
978 | } | |
979 | ||
980 | int __init omap_mux_init(u32 mux_pbase, u32 mux_size, | |
981 | struct omap_mux *superset, | |
982 | struct omap_mux *package_subset, | |
983 | struct omap_board_mux *board_mux, | |
984 | struct omap_ball *package_balls) | |
985 | { | |
986 | if (mux_base) | |
987 | return -EBUSY; | |
988 | ||
4b715efc | 989 | mux_phys = mux_pbase; |
15ac7afe TL |
990 | mux_base = ioremap(mux_pbase, mux_size); |
991 | if (!mux_base) { | |
992 | printk(KERN_ERR "mux: Could not ioremap\n"); | |
993 | return -ENODEV; | |
994 | } | |
995 | ||
996 | #ifdef CONFIG_OMAP_MUX | |
d04eb600 TL |
997 | if (package_subset) |
998 | omap_mux_package_fixup(package_subset, superset); | |
999 | if (package_balls) | |
1000 | omap_mux_package_init_balls(package_balls, superset); | |
15ac7afe TL |
1001 | #endif |
1002 | ||
1003 | omap_mux_init_list(superset); | |
1004 | ||
2cb0c54f TL |
1005 | #ifdef CONFIG_OMAP_MUX |
1006 | omap_mux_set_cmdline_signals(); | |
1007 | omap_mux_set_board_signals(board_mux); | |
1008 | #endif | |
1009 | ||
15ac7afe TL |
1010 | return 0; |
1011 | } | |
1012 | ||
1013 | #endif /* CONFIG_ARCH_OMAP34XX */ | |
15f45e6f | 1014 |