diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-01-06 22:13:58 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-01-06 22:13:58 -0500 |
commit | 01539ba2a706ab7d35fc0667dff919ade7f87d63 (patch) | |
tree | 5a4bd0cf78007d06690fe4ac06bbd49a5a70bc47 /arch/arm/mach-omap2/mux.c | |
parent | 9e9bc9736756f25d6c47b4eba0ebf25b20a6f153 (diff) | |
parent | dc69d1af9e8d9cbbabff88bb35a6782187a22229 (diff) |
Merge branch 'omap-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap-2.6
* 'omap-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap-2.6: (243 commits)
omap2: Make OMAP2PLUS select OMAP_DM_TIMER
OMAP4: hwmod data: Fix alignment and end of line in structurefields
OMAP4: hwmod data: Move the DMA structures
OMAP4: hwmod data: Move the smartreflex structures
OMAP4: hwmod data: Fix missing SIDLE_SMART_WKUP in smartreflexsysc
arm: omap: tusb6010: add name for MUSB IRQ
arm: omap: craneboard: Add USB EHCI support
omap2+: Initialize serial port for dynamic remuxing for n8x0
omap2+: Add struct omap_board_data and use it for platform level serial init
omap2+: Allow hwmod state changes to mux pads based on the state changes
omap2+: Add support for hwmod specific muxing of devices
omap2+: Add omap_mux_get_by_name
OMAP2: PM: fix compile error when !CONFIG_SUSPEND
MAINTAINERS: OMAP: hwmod: update hwmod code, data maintainership
OMAP4: Smartreflex framework extensions
OMAP4: hwmod: Add inital data for smartreflex modules.
OMAP4: PM: Program correct init voltages for scalable VDDs
OMAP4: Adding voltage driver support
OMAP4: Register voltage PMIC parameters with the voltage layer
OMAP3: PM: Program correct init voltages for VDD1 and VDD2
...
Fix up trivial conflict in arch/arm/plat-omap/Kconfig
Diffstat (limited to 'arch/arm/mach-omap2/mux.c')
-rw-r--r-- | arch/arm/mach-omap2/mux.c | 525 |
1 files changed, 395 insertions, 130 deletions
diff --git a/arch/arm/mach-omap2/mux.c b/arch/arm/mach-omap2/mux.c index 074536ae401f..17bd6394d224 100644 --- a/arch/arm/mach-omap2/mux.c +++ b/arch/arm/mach-omap2/mux.c | |||
@@ -1,9 +1,9 @@ | |||
1 | /* | 1 | /* |
2 | * linux/arch/arm/mach-omap2/mux.c | 2 | * linux/arch/arm/mach-omap2/mux.c |
3 | * | 3 | * |
4 | * OMAP2 and OMAP3 pin multiplexing configurations | 4 | * OMAP2, OMAP3 and OMAP4 pin multiplexing configurations |
5 | * | 5 | * |
6 | * Copyright (C) 2004 - 2008 Texas Instruments Inc. | 6 | * Copyright (C) 2004 - 2010 Texas Instruments Inc. |
7 | * Copyright (C) 2003 - 2008 Nokia Corporation | 7 | * Copyright (C) 2003 - 2008 Nokia Corporation |
8 | * | 8 | * |
9 | * Written by Tony Lindgren | 9 | * Written by Tony Lindgren |
@@ -35,65 +35,79 @@ | |||
35 | 35 | ||
36 | #include <asm/system.h> | 36 | #include <asm/system.h> |
37 | 37 | ||
38 | #include <plat/omap_hwmod.h> | ||
39 | |||
38 | #include "control.h" | 40 | #include "control.h" |
39 | #include "mux.h" | 41 | #include "mux.h" |
40 | 42 | ||
41 | #define OMAP_MUX_BASE_OFFSET 0x30 /* Offset from CTRL_BASE */ | 43 | #define OMAP_MUX_BASE_OFFSET 0x30 /* Offset from CTRL_BASE */ |
42 | #define OMAP_MUX_BASE_SZ 0x5ca | 44 | #define OMAP_MUX_BASE_SZ 0x5ca |
43 | #define MUXABLE_GPIO_MODE3 BIT(0) | ||
44 | 45 | ||
45 | struct omap_mux_entry { | 46 | struct omap_mux_entry { |
46 | struct omap_mux mux; | 47 | struct omap_mux mux; |
47 | struct list_head node; | 48 | struct list_head node; |
48 | }; | 49 | }; |
49 | 50 | ||
50 | static unsigned long mux_phys; | 51 | static LIST_HEAD(mux_partitions); |
51 | static void __iomem *mux_base; | 52 | static DEFINE_MUTEX(muxmode_mutex); |
52 | static u8 omap_mux_flags; | 53 | |
54 | struct omap_mux_partition *omap_mux_get(const char *name) | ||
55 | { | ||
56 | struct omap_mux_partition *partition; | ||
57 | |||
58 | list_for_each_entry(partition, &mux_partitions, node) { | ||
59 | if (!strcmp(name, partition->name)) | ||
60 | return partition; | ||
61 | } | ||
62 | |||
63 | return NULL; | ||
64 | } | ||
53 | 65 | ||
54 | u16 omap_mux_read(u16 reg) | 66 | u16 omap_mux_read(struct omap_mux_partition *partition, u16 reg) |
55 | { | 67 | { |
56 | if (cpu_is_omap24xx()) | 68 | if (partition->flags & OMAP_MUX_REG_8BIT) |
57 | return __raw_readb(mux_base + reg); | 69 | return __raw_readb(partition->base + reg); |
58 | else | 70 | else |
59 | return __raw_readw(mux_base + reg); | 71 | return __raw_readw(partition->base + reg); |
60 | } | 72 | } |
61 | 73 | ||
62 | void omap_mux_write(u16 val, u16 reg) | 74 | void omap_mux_write(struct omap_mux_partition *partition, u16 val, |
75 | u16 reg) | ||
63 | { | 76 | { |
64 | if (cpu_is_omap24xx()) | 77 | if (partition->flags & OMAP_MUX_REG_8BIT) |
65 | __raw_writeb(val, mux_base + reg); | 78 | __raw_writeb(val, partition->base + reg); |
66 | else | 79 | else |
67 | __raw_writew(val, mux_base + reg); | 80 | __raw_writew(val, partition->base + reg); |
68 | } | 81 | } |
69 | 82 | ||
70 | void omap_mux_write_array(struct omap_board_mux *board_mux) | 83 | void omap_mux_write_array(struct omap_mux_partition *partition, |
84 | struct omap_board_mux *board_mux) | ||
71 | { | 85 | { |
72 | while (board_mux->reg_offset != OMAP_MUX_TERMINATOR) { | 86 | while (board_mux->reg_offset != OMAP_MUX_TERMINATOR) { |
73 | omap_mux_write(board_mux->value, board_mux->reg_offset); | 87 | omap_mux_write(partition, board_mux->value, |
88 | board_mux->reg_offset); | ||
74 | board_mux++; | 89 | board_mux++; |
75 | } | 90 | } |
76 | } | 91 | } |
77 | 92 | ||
78 | static LIST_HEAD(muxmodes); | ||
79 | static DEFINE_MUTEX(muxmode_mutex); | ||
80 | |||
81 | #ifdef CONFIG_OMAP_MUX | 93 | #ifdef CONFIG_OMAP_MUX |
82 | 94 | ||
83 | static char *omap_mux_options; | 95 | static char *omap_mux_options; |
84 | 96 | ||
85 | int __init omap_mux_init_gpio(int gpio, int val) | 97 | static int __init _omap_mux_init_gpio(struct omap_mux_partition *partition, |
98 | int gpio, int val) | ||
86 | { | 99 | { |
87 | struct omap_mux_entry *e; | 100 | struct omap_mux_entry *e; |
88 | struct omap_mux *gpio_mux = NULL; | 101 | struct omap_mux *gpio_mux = NULL; |
89 | u16 old_mode; | 102 | u16 old_mode; |
90 | u16 mux_mode; | 103 | u16 mux_mode; |
91 | int found = 0; | 104 | int found = 0; |
105 | struct list_head *muxmodes = &partition->muxmodes; | ||
92 | 106 | ||
93 | if (!gpio) | 107 | if (!gpio) |
94 | return -EINVAL; | 108 | return -EINVAL; |
95 | 109 | ||
96 | list_for_each_entry(e, &muxmodes, node) { | 110 | list_for_each_entry(e, muxmodes, node) { |
97 | struct omap_mux *m = &e->mux; | 111 | struct omap_mux *m = &e->mux; |
98 | if (gpio == m->gpio) { | 112 | if (gpio == m->gpio) { |
99 | gpio_mux = m; | 113 | gpio_mux = m; |
@@ -102,34 +116,52 @@ int __init omap_mux_init_gpio(int gpio, int val) | |||
102 | } | 116 | } |
103 | 117 | ||
104 | if (found == 0) { | 118 | if (found == 0) { |
105 | printk(KERN_ERR "mux: Could not set gpio%i\n", gpio); | 119 | pr_err("%s: Could not set gpio%i\n", __func__, gpio); |
106 | return -ENODEV; | 120 | return -ENODEV; |
107 | } | 121 | } |
108 | 122 | ||
109 | if (found > 1) { | 123 | if (found > 1) { |
110 | printk(KERN_INFO "mux: Multiple gpio paths (%d) for gpio%i\n", | 124 | pr_info("%s: Multiple gpio paths (%d) for gpio%i\n", __func__, |
111 | found, gpio); | 125 | found, gpio); |
112 | return -EINVAL; | 126 | return -EINVAL; |
113 | } | 127 | } |
114 | 128 | ||
115 | old_mode = omap_mux_read(gpio_mux->reg_offset); | 129 | old_mode = omap_mux_read(partition, gpio_mux->reg_offset); |
116 | mux_mode = val & ~(OMAP_MUX_NR_MODES - 1); | 130 | mux_mode = val & ~(OMAP_MUX_NR_MODES - 1); |
117 | if (omap_mux_flags & MUXABLE_GPIO_MODE3) | 131 | if (partition->flags & OMAP_MUX_GPIO_IN_MODE3) |
118 | mux_mode |= OMAP_MUX_MODE3; | 132 | mux_mode |= OMAP_MUX_MODE3; |
119 | else | 133 | else |
120 | mux_mode |= OMAP_MUX_MODE4; | 134 | mux_mode |= OMAP_MUX_MODE4; |
121 | printk(KERN_DEBUG "mux: Setting signal %s.gpio%i 0x%04x -> 0x%04x\n", | 135 | pr_debug("%s: Setting signal %s.gpio%i 0x%04x -> 0x%04x\n", __func__, |
122 | gpio_mux->muxnames[0], gpio, old_mode, mux_mode); | 136 | gpio_mux->muxnames[0], gpio, old_mode, mux_mode); |
123 | omap_mux_write(mux_mode, gpio_mux->reg_offset); | 137 | omap_mux_write(partition, mux_mode, gpio_mux->reg_offset); |
124 | 138 | ||
125 | return 0; | 139 | return 0; |
126 | } | 140 | } |
127 | 141 | ||
128 | int __init omap_mux_init_signal(const char *muxname, int val) | 142 | int __init omap_mux_init_gpio(int gpio, int val) |
143 | { | ||
144 | struct omap_mux_partition *partition; | ||
145 | int ret; | ||
146 | |||
147 | list_for_each_entry(partition, &mux_partitions, node) { | ||
148 | ret = _omap_mux_init_gpio(partition, gpio, val); | ||
149 | if (!ret) | ||
150 | return ret; | ||
151 | } | ||
152 | |||
153 | return -ENODEV; | ||
154 | } | ||
155 | |||
156 | static int __init _omap_mux_get_by_name(struct omap_mux_partition *partition, | ||
157 | const char *muxname, | ||
158 | struct omap_mux **found_mux) | ||
129 | { | 159 | { |
160 | struct omap_mux *mux = NULL; | ||
130 | struct omap_mux_entry *e; | 161 | struct omap_mux_entry *e; |
131 | const char *mode_name; | 162 | const char *mode_name; |
132 | int found = 0, mode0_len = 0; | 163 | int found = 0, found_mode, mode0_len = 0; |
164 | struct list_head *muxmodes = &partition->muxmodes; | ||
133 | 165 | ||
134 | mode_name = strchr(muxname, '.'); | 166 | mode_name = strchr(muxname, '.'); |
135 | if (mode_name) { | 167 | if (mode_name) { |
@@ -139,51 +171,200 @@ int __init omap_mux_init_signal(const char *muxname, int val) | |||
139 | mode_name = muxname; | 171 | mode_name = muxname; |
140 | } | 172 | } |
141 | 173 | ||
142 | list_for_each_entry(e, &muxmodes, node) { | 174 | list_for_each_entry(e, muxmodes, node) { |
143 | struct omap_mux *m = &e->mux; | 175 | char *m0_entry; |
144 | char *m0_entry = m->muxnames[0]; | ||
145 | int i; | 176 | int i; |
146 | 177 | ||
178 | mux = &e->mux; | ||
179 | m0_entry = mux->muxnames[0]; | ||
180 | |||
147 | /* First check for full name in mode0.muxmode format */ | 181 | /* First check for full name in mode0.muxmode format */ |
148 | if (mode0_len && strncmp(muxname, m0_entry, mode0_len)) | 182 | if (mode0_len && strncmp(muxname, m0_entry, mode0_len)) |
149 | continue; | 183 | continue; |
150 | 184 | ||
151 | /* Then check for muxmode only */ | 185 | /* Then check for muxmode only */ |
152 | for (i = 0; i < OMAP_MUX_NR_MODES; i++) { | 186 | for (i = 0; i < OMAP_MUX_NR_MODES; i++) { |
153 | char *mode_cur = m->muxnames[i]; | 187 | char *mode_cur = mux->muxnames[i]; |
154 | 188 | ||
155 | if (!mode_cur) | 189 | if (!mode_cur) |
156 | continue; | 190 | continue; |
157 | 191 | ||
158 | if (!strcmp(mode_name, mode_cur)) { | 192 | if (!strcmp(mode_name, mode_cur)) { |
159 | u16 old_mode; | 193 | *found_mux = mux; |
160 | u16 mux_mode; | ||
161 | |||
162 | old_mode = omap_mux_read(m->reg_offset); | ||
163 | mux_mode = val | i; | ||
164 | printk(KERN_DEBUG "mux: Setting signal " | ||
165 | "%s.%s 0x%04x -> 0x%04x\n", | ||
166 | m0_entry, muxname, old_mode, mux_mode); | ||
167 | omap_mux_write(mux_mode, m->reg_offset); | ||
168 | found++; | 194 | found++; |
195 | found_mode = i; | ||
169 | } | 196 | } |
170 | } | 197 | } |
171 | } | 198 | } |
172 | 199 | ||
173 | if (found == 1) | 200 | if (found == 1) { |
174 | return 0; | 201 | return found_mode; |
202 | } | ||
175 | 203 | ||
176 | if (found > 1) { | 204 | if (found > 1) { |
177 | printk(KERN_ERR "mux: Multiple signal paths (%i) for %s\n", | 205 | pr_err("%s: Multiple signal paths (%i) for %s\n", __func__, |
178 | found, muxname); | 206 | found, muxname); |
179 | return -EINVAL; | 207 | return -EINVAL; |
180 | } | 208 | } |
181 | 209 | ||
182 | printk(KERN_ERR "mux: Could not set signal %s\n", muxname); | 210 | pr_err("%s: Could not find signal %s\n", __func__, muxname); |
183 | 211 | ||
184 | return -ENODEV; | 212 | return -ENODEV; |
185 | } | 213 | } |
186 | 214 | ||
215 | static int __init | ||
216 | omap_mux_get_by_name(const char *muxname, | ||
217 | struct omap_mux_partition **found_partition, | ||
218 | struct omap_mux **found_mux) | ||
219 | { | ||
220 | struct omap_mux_partition *partition; | ||
221 | |||
222 | list_for_each_entry(partition, &mux_partitions, node) { | ||
223 | struct omap_mux *mux = NULL; | ||
224 | int mux_mode = _omap_mux_get_by_name(partition, muxname, &mux); | ||
225 | if (mux_mode < 0) | ||
226 | continue; | ||
227 | |||
228 | *found_partition = partition; | ||
229 | *found_mux = mux; | ||
230 | |||
231 | return mux_mode; | ||
232 | } | ||
233 | |||
234 | return -ENODEV; | ||
235 | } | ||
236 | |||
237 | int __init omap_mux_init_signal(const char *muxname, int val) | ||
238 | { | ||
239 | struct omap_mux_partition *partition = NULL; | ||
240 | struct omap_mux *mux = NULL; | ||
241 | u16 old_mode; | ||
242 | int mux_mode; | ||
243 | |||
244 | mux_mode = omap_mux_get_by_name(muxname, &partition, &mux); | ||
245 | if (mux_mode < 0) | ||
246 | return mux_mode; | ||
247 | |||
248 | old_mode = omap_mux_read(partition, mux->reg_offset); | ||
249 | mux_mode |= val; | ||
250 | pr_debug("%s: Setting signal %s 0x%04x -> 0x%04x\n", | ||
251 | __func__, muxname, old_mode, mux_mode); | ||
252 | omap_mux_write(partition, mux_mode, mux->reg_offset); | ||
253 | |||
254 | return 0; | ||
255 | } | ||
256 | |||
257 | struct omap_hwmod_mux_info * __init | ||
258 | omap_hwmod_mux_init(struct omap_device_pad *bpads, int nr_pads) | ||
259 | { | ||
260 | struct omap_hwmod_mux_info *hmux; | ||
261 | int i; | ||
262 | |||
263 | if (!bpads || nr_pads < 1) | ||
264 | return NULL; | ||
265 | |||
266 | hmux = kzalloc(sizeof(struct omap_hwmod_mux_info), GFP_KERNEL); | ||
267 | if (!hmux) | ||
268 | goto err1; | ||
269 | |||
270 | hmux->nr_pads = nr_pads; | ||
271 | |||
272 | hmux->pads = kzalloc(sizeof(struct omap_device_pad) * | ||
273 | nr_pads, GFP_KERNEL); | ||
274 | if (!hmux->pads) | ||
275 | goto err2; | ||
276 | |||
277 | for (i = 0; i < hmux->nr_pads; i++) { | ||
278 | struct omap_mux_partition *partition; | ||
279 | struct omap_device_pad *bpad = &bpads[i], *pad = &hmux->pads[i]; | ||
280 | struct omap_mux *mux; | ||
281 | int mux_mode; | ||
282 | |||
283 | mux_mode = omap_mux_get_by_name(bpad->name, &partition, &mux); | ||
284 | if (mux_mode < 0) | ||
285 | goto err3; | ||
286 | if (!pad->partition) | ||
287 | pad->partition = partition; | ||
288 | if (!pad->mux) | ||
289 | pad->mux = mux; | ||
290 | |||
291 | pad->name = kzalloc(strlen(bpad->name) + 1, GFP_KERNEL); | ||
292 | if (!pad->name) { | ||
293 | int j; | ||
294 | |||
295 | for (j = i - 1; j >= 0; j--) | ||
296 | kfree(hmux->pads[j].name); | ||
297 | goto err3; | ||
298 | } | ||
299 | strcpy(pad->name, bpad->name); | ||
300 | |||
301 | pad->flags = bpad->flags; | ||
302 | pad->enable = bpad->enable; | ||
303 | pad->idle = bpad->idle; | ||
304 | pad->off = bpad->off; | ||
305 | pr_debug("%s: Initialized %s\n", __func__, pad->name); | ||
306 | } | ||
307 | |||
308 | return hmux; | ||
309 | |||
310 | err3: | ||
311 | kfree(hmux->pads); | ||
312 | err2: | ||
313 | kfree(hmux); | ||
314 | err1: | ||
315 | pr_err("%s: Could not allocate device mux entry\n", __func__); | ||
316 | |||
317 | return NULL; | ||
318 | } | ||
319 | |||
320 | /* Assumes the calling function takes care of locking */ | ||
321 | void omap_hwmod_mux(struct omap_hwmod_mux_info *hmux, u8 state) | ||
322 | { | ||
323 | int i; | ||
324 | |||
325 | for (i = 0; i < hmux->nr_pads; i++) { | ||
326 | struct omap_device_pad *pad = &hmux->pads[i]; | ||
327 | int flags, val = -EINVAL; | ||
328 | |||
329 | flags = pad->flags; | ||
330 | |||
331 | switch (state) { | ||
332 | case _HWMOD_STATE_ENABLED: | ||
333 | if (flags & OMAP_DEVICE_PAD_ENABLED) | ||
334 | break; | ||
335 | flags |= OMAP_DEVICE_PAD_ENABLED; | ||
336 | val = pad->enable; | ||
337 | pr_debug("%s: Enabling %s %x\n", __func__, | ||
338 | pad->name, val); | ||
339 | break; | ||
340 | case _HWMOD_STATE_IDLE: | ||
341 | if (!(flags & OMAP_DEVICE_PAD_REMUX)) | ||
342 | break; | ||
343 | flags &= ~OMAP_DEVICE_PAD_ENABLED; | ||
344 | val = pad->idle; | ||
345 | pr_debug("%s: Idling %s %x\n", __func__, | ||
346 | pad->name, val); | ||
347 | break; | ||
348 | case _HWMOD_STATE_DISABLED: | ||
349 | default: | ||
350 | /* Use safe mode unless OMAP_DEVICE_PAD_REMUX */ | ||
351 | if (flags & OMAP_DEVICE_PAD_REMUX) | ||
352 | val = pad->off; | ||
353 | else | ||
354 | val = OMAP_MUX_MODE7; | ||
355 | flags &= ~OMAP_DEVICE_PAD_ENABLED; | ||
356 | pr_debug("%s: Disabling %s %x\n", __func__, | ||
357 | pad->name, val); | ||
358 | }; | ||
359 | |||
360 | if (val >= 0) { | ||
361 | omap_mux_write(pad->partition, val, | ||
362 | pad->mux->reg_offset); | ||
363 | pad->flags = flags; | ||
364 | } | ||
365 | } | ||
366 | } | ||
367 | |||
187 | #ifdef CONFIG_DEBUG_FS | 368 | #ifdef CONFIG_DEBUG_FS |
188 | 369 | ||
189 | #define OMAP_MUX_MAX_NR_FLAGS 10 | 370 | #define OMAP_MUX_MAX_NR_FLAGS 10 |
@@ -248,13 +429,15 @@ static inline void omap_mux_decode(struct seq_file *s, u16 val) | |||
248 | } while (i-- > 0); | 429 | } while (i-- > 0); |
249 | } | 430 | } |
250 | 431 | ||
251 | #define OMAP_MUX_DEFNAME_LEN 16 | 432 | #define OMAP_MUX_DEFNAME_LEN 32 |
252 | 433 | ||
253 | static int omap_mux_dbg_board_show(struct seq_file *s, void *unused) | 434 | static int omap_mux_dbg_board_show(struct seq_file *s, void *unused) |
254 | { | 435 | { |
436 | struct omap_mux_partition *partition = s->private; | ||
255 | struct omap_mux_entry *e; | 437 | struct omap_mux_entry *e; |
438 | u8 omap_gen = omap_rev() >> 28; | ||
256 | 439 | ||
257 | list_for_each_entry(e, &muxmodes, node) { | 440 | list_for_each_entry(e, &partition->muxmodes, node) { |
258 | struct omap_mux *m = &e->mux; | 441 | struct omap_mux *m = &e->mux; |
259 | char m0_def[OMAP_MUX_DEFNAME_LEN]; | 442 | char m0_def[OMAP_MUX_DEFNAME_LEN]; |
260 | char *m0_name = m->muxnames[0]; | 443 | char *m0_name = m->muxnames[0]; |
@@ -272,11 +455,16 @@ static int omap_mux_dbg_board_show(struct seq_file *s, void *unused) | |||
272 | } | 455 | } |
273 | m0_def[i] = toupper(m0_name[i]); | 456 | m0_def[i] = toupper(m0_name[i]); |
274 | } | 457 | } |
275 | val = omap_mux_read(m->reg_offset); | 458 | val = omap_mux_read(partition, m->reg_offset); |
276 | mode = val & OMAP_MUX_MODE7; | 459 | mode = val & OMAP_MUX_MODE7; |
277 | 460 | if (mode != 0) | |
278 | seq_printf(s, "OMAP%i_MUX(%s, ", | 461 | seq_printf(s, "/* %s */\n", m->muxnames[mode]); |
279 | cpu_is_omap34xx() ? 3 : 0, m0_def); | 462 | |
463 | /* | ||
464 | * XXX: Might be revisited to support differences accross | ||
465 | * same OMAP generation. | ||
466 | */ | ||
467 | seq_printf(s, "OMAP%d_MUX(%s, ", omap_gen, m0_def); | ||
280 | omap_mux_decode(s, val); | 468 | omap_mux_decode(s, val); |
281 | seq_printf(s, "),\n"); | 469 | seq_printf(s, "),\n"); |
282 | } | 470 | } |
@@ -286,7 +474,7 @@ static int omap_mux_dbg_board_show(struct seq_file *s, void *unused) | |||
286 | 474 | ||
287 | static int omap_mux_dbg_board_open(struct inode *inode, struct file *file) | 475 | static int omap_mux_dbg_board_open(struct inode *inode, struct file *file) |
288 | { | 476 | { |
289 | return single_open(file, omap_mux_dbg_board_show, &inode->i_private); | 477 | return single_open(file, omap_mux_dbg_board_show, inode->i_private); |
290 | } | 478 | } |
291 | 479 | ||
292 | static const struct file_operations omap_mux_dbg_board_fops = { | 480 | static const struct file_operations omap_mux_dbg_board_fops = { |
@@ -296,19 +484,43 @@ static const struct file_operations omap_mux_dbg_board_fops = { | |||
296 | .release = single_release, | 484 | .release = single_release, |
297 | }; | 485 | }; |
298 | 486 | ||
487 | static struct omap_mux_partition *omap_mux_get_partition(struct omap_mux *mux) | ||
488 | { | ||
489 | struct omap_mux_partition *partition; | ||
490 | |||
491 | list_for_each_entry(partition, &mux_partitions, node) { | ||
492 | struct list_head *muxmodes = &partition->muxmodes; | ||
493 | struct omap_mux_entry *e; | ||
494 | |||
495 | list_for_each_entry(e, muxmodes, node) { | ||
496 | struct omap_mux *m = &e->mux; | ||
497 | |||
498 | if (m == mux) | ||
499 | return partition; | ||
500 | } | ||
501 | } | ||
502 | |||
503 | return NULL; | ||
504 | } | ||
505 | |||
299 | static int omap_mux_dbg_signal_show(struct seq_file *s, void *unused) | 506 | static int omap_mux_dbg_signal_show(struct seq_file *s, void *unused) |
300 | { | 507 | { |
301 | struct omap_mux *m = s->private; | 508 | struct omap_mux *m = s->private; |
509 | struct omap_mux_partition *partition; | ||
302 | const char *none = "NA"; | 510 | const char *none = "NA"; |
303 | u16 val; | 511 | u16 val; |
304 | int mode; | 512 | int mode; |
305 | 513 | ||
306 | val = omap_mux_read(m->reg_offset); | 514 | partition = omap_mux_get_partition(m); |
515 | if (!partition) | ||
516 | return 0; | ||
517 | |||
518 | val = omap_mux_read(partition, m->reg_offset); | ||
307 | mode = val & OMAP_MUX_MODE7; | 519 | mode = val & OMAP_MUX_MODE7; |
308 | 520 | ||
309 | seq_printf(s, "name: %s.%s (0x%08lx/0x%03x = 0x%04x), b %s, t %s\n", | 521 | seq_printf(s, "name: %s.%s (0x%08x/0x%03x = 0x%04x), b %s, t %s\n", |
310 | m->muxnames[0], m->muxnames[mode], | 522 | m->muxnames[0], m->muxnames[mode], |
311 | mux_phys + m->reg_offset, m->reg_offset, val, | 523 | partition->phys + m->reg_offset, m->reg_offset, val, |
312 | m->balls[0] ? m->balls[0] : none, | 524 | m->balls[0] ? m->balls[0] : none, |
313 | m->balls[1] ? m->balls[1] : none); | 525 | m->balls[1] ? m->balls[1] : none); |
314 | seq_printf(s, "mode: "); | 526 | seq_printf(s, "mode: "); |
@@ -330,14 +542,15 @@ static int omap_mux_dbg_signal_show(struct seq_file *s, void *unused) | |||
330 | #define OMAP_MUX_MAX_ARG_CHAR 7 | 542 | #define OMAP_MUX_MAX_ARG_CHAR 7 |
331 | 543 | ||
332 | static ssize_t omap_mux_dbg_signal_write(struct file *file, | 544 | static ssize_t omap_mux_dbg_signal_write(struct file *file, |
333 | const char __user *user_buf, | 545 | const char __user *user_buf, |
334 | size_t count, loff_t *ppos) | 546 | size_t count, loff_t *ppos) |
335 | { | 547 | { |
336 | char buf[OMAP_MUX_MAX_ARG_CHAR]; | 548 | char buf[OMAP_MUX_MAX_ARG_CHAR]; |
337 | struct seq_file *seqf; | 549 | struct seq_file *seqf; |
338 | struct omap_mux *m; | 550 | struct omap_mux *m; |
339 | unsigned long val; | 551 | unsigned long val; |
340 | int buf_size, ret; | 552 | int buf_size, ret; |
553 | struct omap_mux_partition *partition; | ||
341 | 554 | ||
342 | if (count > OMAP_MUX_MAX_ARG_CHAR) | 555 | if (count > OMAP_MUX_MAX_ARG_CHAR) |
343 | return -EINVAL; | 556 | return -EINVAL; |
@@ -358,7 +571,11 @@ static ssize_t omap_mux_dbg_signal_write(struct file *file, | |||
358 | seqf = file->private_data; | 571 | seqf = file->private_data; |
359 | m = seqf->private; | 572 | m = seqf->private; |
360 | 573 | ||
361 | omap_mux_write((u16)val, m->reg_offset); | 574 | partition = omap_mux_get_partition(m); |
575 | if (!partition) | ||
576 | return -ENODEV; | ||
577 | |||
578 | omap_mux_write(partition, (u16)val, m->reg_offset); | ||
362 | *ppos += count; | 579 | *ppos += count; |
363 | 580 | ||
364 | return count; | 581 | return count; |
@@ -379,22 +596,38 @@ static const struct file_operations omap_mux_dbg_signal_fops = { | |||
379 | 596 | ||
380 | static struct dentry *mux_dbg_dir; | 597 | static struct dentry *mux_dbg_dir; |
381 | 598 | ||
382 | static void __init omap_mux_dbg_init(void) | 599 | static void __init omap_mux_dbg_create_entry( |
600 | struct omap_mux_partition *partition, | ||
601 | struct dentry *mux_dbg_dir) | ||
383 | { | 602 | { |
384 | struct omap_mux_entry *e; | 603 | struct omap_mux_entry *e; |
385 | 604 | ||
605 | list_for_each_entry(e, &partition->muxmodes, node) { | ||
606 | struct omap_mux *m = &e->mux; | ||
607 | |||
608 | (void)debugfs_create_file(m->muxnames[0], S_IWUGO, mux_dbg_dir, | ||
609 | m, &omap_mux_dbg_signal_fops); | ||
610 | } | ||
611 | } | ||
612 | |||
613 | static void __init omap_mux_dbg_init(void) | ||
614 | { | ||
615 | struct omap_mux_partition *partition; | ||
616 | static struct dentry *mux_dbg_board_dir; | ||
617 | |||
386 | mux_dbg_dir = debugfs_create_dir("omap_mux", NULL); | 618 | mux_dbg_dir = debugfs_create_dir("omap_mux", NULL); |
387 | if (!mux_dbg_dir) | 619 | if (!mux_dbg_dir) |
388 | return; | 620 | return; |
389 | 621 | ||
390 | (void)debugfs_create_file("board", S_IRUGO, mux_dbg_dir, | 622 | mux_dbg_board_dir = debugfs_create_dir("board", mux_dbg_dir); |
391 | NULL, &omap_mux_dbg_board_fops); | 623 | if (!mux_dbg_board_dir) |
392 | 624 | return; | |
393 | list_for_each_entry(e, &muxmodes, node) { | ||
394 | struct omap_mux *m = &e->mux; | ||
395 | 625 | ||
396 | (void)debugfs_create_file(m->muxnames[0], S_IWUGO, mux_dbg_dir, | 626 | list_for_each_entry(partition, &mux_partitions, node) { |
397 | m, &omap_mux_dbg_signal_fops); | 627 | omap_mux_dbg_create_entry(partition, mux_dbg_dir); |
628 | (void)debugfs_create_file(partition->name, S_IRUGO, | ||
629 | mux_dbg_board_dir, partition, | ||
630 | &omap_mux_dbg_board_fops); | ||
398 | } | 631 | } |
399 | } | 632 | } |
400 | 633 | ||
@@ -421,23 +654,25 @@ static void __init omap_mux_free_names(struct omap_mux *m) | |||
421 | /* Free all data except for GPIO pins unless CONFIG_DEBUG_FS is set */ | 654 | /* Free all data except for GPIO pins unless CONFIG_DEBUG_FS is set */ |
422 | static int __init omap_mux_late_init(void) | 655 | static int __init omap_mux_late_init(void) |
423 | { | 656 | { |
424 | struct omap_mux_entry *e, *tmp; | 657 | struct omap_mux_partition *partition; |
425 | 658 | ||
426 | list_for_each_entry_safe(e, tmp, &muxmodes, node) { | 659 | list_for_each_entry(partition, &mux_partitions, node) { |
427 | struct omap_mux *m = &e->mux; | 660 | struct omap_mux_entry *e, *tmp; |
428 | u16 mode = omap_mux_read(m->reg_offset); | 661 | list_for_each_entry_safe(e, tmp, &partition->muxmodes, node) { |
662 | struct omap_mux *m = &e->mux; | ||
663 | u16 mode = omap_mux_read(partition, m->reg_offset); | ||
429 | 664 | ||
430 | if (OMAP_MODE_GPIO(mode)) | 665 | if (OMAP_MODE_GPIO(mode)) |
431 | continue; | 666 | continue; |
432 | 667 | ||
433 | #ifndef CONFIG_DEBUG_FS | 668 | #ifndef CONFIG_DEBUG_FS |
434 | mutex_lock(&muxmode_mutex); | 669 | mutex_lock(&muxmode_mutex); |
435 | list_del(&e->node); | 670 | list_del(&e->node); |
436 | mutex_unlock(&muxmode_mutex); | 671 | mutex_unlock(&muxmode_mutex); |
437 | omap_mux_free_names(m); | 672 | omap_mux_free_names(m); |
438 | kfree(m); | 673 | kfree(m); |
439 | #endif | 674 | #endif |
440 | 675 | } | |
441 | } | 676 | } |
442 | 677 | ||
443 | omap_mux_dbg_init(); | 678 | omap_mux_dbg_init(); |
@@ -462,8 +697,8 @@ static void __init omap_mux_package_fixup(struct omap_mux *p, | |||
462 | s++; | 697 | s++; |
463 | } | 698 | } |
464 | if (!found) | 699 | if (!found) |
465 | printk(KERN_ERR "mux: Unknown entry offset 0x%x\n", | 700 | pr_err("%s: Unknown entry offset 0x%x\n", __func__, |
466 | p->reg_offset); | 701 | p->reg_offset); |
467 | p++; | 702 | p++; |
468 | } | 703 | } |
469 | } | 704 | } |
@@ -487,8 +722,8 @@ static void __init omap_mux_package_init_balls(struct omap_ball *b, | |||
487 | s++; | 722 | s++; |
488 | } | 723 | } |
489 | if (!found) | 724 | if (!found) |
490 | printk(KERN_ERR "mux: Unknown ball offset 0x%x\n", | 725 | pr_err("%s: Unknown ball offset 0x%x\n", __func__, |
491 | b->reg_offset); | 726 | b->reg_offset); |
492 | b++; | 727 | b++; |
493 | } | 728 | } |
494 | } | 729 | } |
@@ -554,7 +789,7 @@ static void __init omap_mux_set_cmdline_signals(void) | |||
554 | } | 789 | } |
555 | 790 | ||
556 | static int __init omap_mux_copy_names(struct omap_mux *src, | 791 | static int __init omap_mux_copy_names(struct omap_mux *src, |
557 | struct omap_mux *dst) | 792 | struct omap_mux *dst) |
558 | { | 793 | { |
559 | int i; | 794 | int i; |
560 | 795 | ||
@@ -592,51 +827,63 @@ free: | |||
592 | 827 | ||
593 | #endif /* CONFIG_OMAP_MUX */ | 828 | #endif /* CONFIG_OMAP_MUX */ |
594 | 829 | ||
595 | static u16 omap_mux_get_by_gpio(int gpio) | 830 | static struct omap_mux *omap_mux_get_by_gpio( |
831 | struct omap_mux_partition *partition, | ||
832 | int gpio) | ||
596 | { | 833 | { |
597 | struct omap_mux_entry *e; | 834 | struct omap_mux_entry *e; |
598 | u16 offset = OMAP_MUX_TERMINATOR; | 835 | struct omap_mux *ret = NULL; |
599 | 836 | ||
600 | list_for_each_entry(e, &muxmodes, node) { | 837 | list_for_each_entry(e, &partition->muxmodes, node) { |
601 | struct omap_mux *m = &e->mux; | 838 | struct omap_mux *m = &e->mux; |
602 | if (m->gpio == gpio) { | 839 | if (m->gpio == gpio) { |
603 | offset = m->reg_offset; | 840 | ret = m; |
604 | break; | 841 | break; |
605 | } | 842 | } |
606 | } | 843 | } |
607 | 844 | ||
608 | return offset; | 845 | return ret; |
609 | } | 846 | } |
610 | 847 | ||
611 | /* Needed for dynamic muxing of GPIO pins for off-idle */ | 848 | /* Needed for dynamic muxing of GPIO pins for off-idle */ |
612 | u16 omap_mux_get_gpio(int gpio) | 849 | u16 omap_mux_get_gpio(int gpio) |
613 | { | 850 | { |
614 | u16 offset; | 851 | struct omap_mux_partition *partition; |
852 | struct omap_mux *m; | ||
615 | 853 | ||
616 | offset = omap_mux_get_by_gpio(gpio); | 854 | list_for_each_entry(partition, &mux_partitions, node) { |
617 | if (offset == OMAP_MUX_TERMINATOR) { | 855 | m = omap_mux_get_by_gpio(partition, gpio); |
618 | printk(KERN_ERR "mux: Could not get gpio%i\n", gpio); | 856 | if (m) |
619 | return offset; | 857 | return omap_mux_read(partition, m->reg_offset); |
620 | } | 858 | } |
621 | 859 | ||
622 | return omap_mux_read(offset); | 860 | if (!m || m->reg_offset == OMAP_MUX_TERMINATOR) |
861 | pr_err("%s: Could not get gpio%i\n", __func__, gpio); | ||
862 | |||
863 | return OMAP_MUX_TERMINATOR; | ||
623 | } | 864 | } |
624 | 865 | ||
625 | /* Needed for dynamic muxing of GPIO pins for off-idle */ | 866 | /* Needed for dynamic muxing of GPIO pins for off-idle */ |
626 | void omap_mux_set_gpio(u16 val, int gpio) | 867 | void omap_mux_set_gpio(u16 val, int gpio) |
627 | { | 868 | { |
628 | u16 offset; | 869 | struct omap_mux_partition *partition; |
870 | struct omap_mux *m = NULL; | ||
629 | 871 | ||
630 | offset = omap_mux_get_by_gpio(gpio); | 872 | list_for_each_entry(partition, &mux_partitions, node) { |
631 | if (offset == OMAP_MUX_TERMINATOR) { | 873 | m = omap_mux_get_by_gpio(partition, gpio); |
632 | printk(KERN_ERR "mux: Could not set gpio%i\n", gpio); | 874 | if (m) { |
633 | return; | 875 | omap_mux_write(partition, val, m->reg_offset); |
876 | return; | ||
877 | } | ||
634 | } | 878 | } |
635 | 879 | ||
636 | omap_mux_write(val, offset); | 880 | if (!m || m->reg_offset == OMAP_MUX_TERMINATOR) |
881 | pr_err("%s: Could not set gpio%i\n", __func__, gpio); | ||
637 | } | 882 | } |
638 | 883 | ||
639 | static struct omap_mux * __init omap_mux_list_add(struct omap_mux *src) | 884 | static struct omap_mux * __init omap_mux_list_add( |
885 | struct omap_mux_partition *partition, | ||
886 | struct omap_mux *src) | ||
640 | { | 887 | { |
641 | struct omap_mux_entry *entry; | 888 | struct omap_mux_entry *entry; |
642 | struct omap_mux *m; | 889 | struct omap_mux *m; |
@@ -656,7 +903,7 @@ static struct omap_mux * __init omap_mux_list_add(struct omap_mux *src) | |||
656 | #endif | 903 | #endif |
657 | 904 | ||
658 | mutex_lock(&muxmode_mutex); | 905 | mutex_lock(&muxmode_mutex); |
659 | list_add_tail(&entry->node, &muxmodes); | 906 | list_add_tail(&entry->node, &partition->muxmodes); |
660 | mutex_unlock(&muxmode_mutex); | 907 | mutex_unlock(&muxmode_mutex); |
661 | 908 | ||
662 | return m; | 909 | return m; |
@@ -667,7 +914,8 @@ static struct omap_mux * __init omap_mux_list_add(struct omap_mux *src) | |||
667 | * the GPIO to mux offset mapping that is needed for dynamic muxing | 914 | * the GPIO to mux offset mapping that is needed for dynamic muxing |
668 | * of GPIO pins for off-idle. | 915 | * of GPIO pins for off-idle. |
669 | */ | 916 | */ |
670 | static void __init omap_mux_init_list(struct omap_mux *superset) | 917 | static void __init omap_mux_init_list(struct omap_mux_partition *partition, |
918 | struct omap_mux *superset) | ||
671 | { | 919 | { |
672 | while (superset->reg_offset != OMAP_MUX_TERMINATOR) { | 920 | while (superset->reg_offset != OMAP_MUX_TERMINATOR) { |
673 | struct omap_mux *entry; | 921 | struct omap_mux *entry; |
@@ -679,15 +927,16 @@ static void __init omap_mux_init_list(struct omap_mux *superset) | |||
679 | } | 927 | } |
680 | #else | 928 | #else |
681 | /* Skip pins that are not muxed as GPIO by bootloader */ | 929 | /* Skip pins that are not muxed as GPIO by bootloader */ |
682 | if (!OMAP_MODE_GPIO(omap_mux_read(superset->reg_offset))) { | 930 | if (!OMAP_MODE_GPIO(omap_mux_read(partition, |
931 | superset->reg_offset))) { | ||
683 | superset++; | 932 | superset++; |
684 | continue; | 933 | continue; |
685 | } | 934 | } |
686 | #endif | 935 | #endif |
687 | 936 | ||
688 | entry = omap_mux_list_add(superset); | 937 | entry = omap_mux_list_add(partition, superset); |
689 | if (!entry) { | 938 | if (!entry) { |
690 | printk(KERN_ERR "mux: Could not add entry\n"); | 939 | pr_err("%s: Could not add entry\n", __func__); |
691 | return; | 940 | return; |
692 | } | 941 | } |
693 | superset++; | 942 | superset++; |
@@ -706,10 +955,11 @@ static void omap_mux_init_package(struct omap_mux *superset, | |||
706 | omap_mux_package_init_balls(package_balls, superset); | 955 | omap_mux_package_init_balls(package_balls, superset); |
707 | } | 956 | } |
708 | 957 | ||
709 | static void omap_mux_init_signals(struct omap_board_mux *board_mux) | 958 | static void omap_mux_init_signals(struct omap_mux_partition *partition, |
959 | struct omap_board_mux *board_mux) | ||
710 | { | 960 | { |
711 | omap_mux_set_cmdline_signals(); | 961 | omap_mux_set_cmdline_signals(); |
712 | omap_mux_write_array(board_mux); | 962 | omap_mux_write_array(partition, board_mux); |
713 | } | 963 | } |
714 | 964 | ||
715 | #else | 965 | #else |
@@ -720,34 +970,49 @@ static void omap_mux_init_package(struct omap_mux *superset, | |||
720 | { | 970 | { |
721 | } | 971 | } |
722 | 972 | ||
723 | static void omap_mux_init_signals(struct omap_board_mux *board_mux) | 973 | static void omap_mux_init_signals(struct omap_mux_partition *partition, |
974 | struct omap_board_mux *board_mux) | ||
724 | { | 975 | { |
725 | } | 976 | } |
726 | 977 | ||
727 | #endif | 978 | #endif |
728 | 979 | ||
729 | int __init omap_mux_init(u32 mux_pbase, u32 mux_size, | 980 | static u32 mux_partitions_cnt; |
730 | struct omap_mux *superset, | ||
731 | struct omap_mux *package_subset, | ||
732 | struct omap_board_mux *board_mux, | ||
733 | struct omap_ball *package_balls) | ||
734 | { | ||
735 | if (mux_base) | ||
736 | return -EBUSY; | ||
737 | 981 | ||
738 | mux_phys = mux_pbase; | 982 | int __init omap_mux_init(const char *name, u32 flags, |
739 | mux_base = ioremap(mux_pbase, mux_size); | 983 | u32 mux_pbase, u32 mux_size, |
740 | if (!mux_base) { | 984 | struct omap_mux *superset, |
741 | printk(KERN_ERR "mux: Could not ioremap\n"); | 985 | struct omap_mux *package_subset, |
986 | struct omap_board_mux *board_mux, | ||
987 | struct omap_ball *package_balls) | ||
988 | { | ||
989 | struct omap_mux_partition *partition; | ||
990 | |||
991 | partition = kzalloc(sizeof(struct omap_mux_partition), GFP_KERNEL); | ||
992 | if (!partition) | ||
993 | return -ENOMEM; | ||
994 | |||
995 | partition->name = name; | ||
996 | partition->flags = flags; | ||
997 | partition->size = mux_size; | ||
998 | partition->phys = mux_pbase; | ||
999 | partition->base = ioremap(mux_pbase, mux_size); | ||
1000 | if (!partition->base) { | ||
1001 | pr_err("%s: Could not ioremap mux partition at 0x%08x\n", | ||
1002 | __func__, partition->phys); | ||
742 | return -ENODEV; | 1003 | return -ENODEV; |
743 | } | 1004 | } |
744 | 1005 | ||
745 | if (cpu_is_omap24xx()) | 1006 | INIT_LIST_HEAD(&partition->muxmodes); |
746 | omap_mux_flags = MUXABLE_GPIO_MODE3; | 1007 | |
1008 | list_add_tail(&partition->node, &mux_partitions); | ||
1009 | mux_partitions_cnt++; | ||
1010 | pr_info("%s: Add partition: #%d: %s, flags: %x\n", __func__, | ||
1011 | mux_partitions_cnt, partition->name, partition->flags); | ||
747 | 1012 | ||
748 | omap_mux_init_package(superset, package_subset, package_balls); | 1013 | omap_mux_init_package(superset, package_subset, package_balls); |
749 | omap_mux_init_list(superset); | 1014 | omap_mux_init_list(partition, superset); |
750 | omap_mux_init_signals(board_mux); | 1015 | omap_mux_init_signals(partition, board_mux); |
751 | 1016 | ||
752 | return 0; | 1017 | return 0; |
753 | } | 1018 | } |