blob: e33740c091be0727ac3dc91fd4bae3121a1c601f [file] [log] [blame]
Tony Lindgren1dbae812005-11-10 14:26:51 +00001/*
2 * linux/arch/arm/mach-omap2/mux.c
3 *
Vikram Pandita23518722008-10-06 15:49:16 +03004 * OMAP2 and OMAP3 pin multiplexing configurations
Tony Lindgren1dbae812005-11-10 14:26:51 +00005 *
Tony Lindgren93308992008-01-24 17:24:15 -08006 * Copyright (C) 2004 - 2008 Texas Instruments Inc.
7 * Copyright (C) 2003 - 2008 Nokia Corporation
Tony Lindgren1dbae812005-11-10 14:26:51 +00008 *
Tony Lindgren93308992008-01-24 17:24:15 -08009 * Written by Tony Lindgren
Tony Lindgren1dbae812005-11-10 14:26:51 +000010 *
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 */
Tony Lindgren1dbae812005-11-10 14:26:51 +000026#include <linux/module.h>
27#include <linux/init.h>
Russell Kingfced80c2008-09-06 12:10:45 +010028#include <linux/io.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090029#include <linux/slab.h>
Tony Lindgren1dbae812005-11-10 14:26:51 +000030#include <linux/spinlock.h>
Tony Lindgren15ac7af2009-12-11 16:16:32 -080031#include <linux/list.h>
Tony Lindgren4b715ef2009-12-11 16:16:32 -080032#include <linux/ctype.h>
33#include <linux/debugfs.h>
34#include <linux/seq_file.h>
35#include <linux/uaccess.h>
Tony Lindgren1dbae812005-11-10 14:26:51 +000036
Russell Kingfced80c2008-09-06 12:10:45 +010037#include <asm/system.h>
38
Tony Lindgrence491cf2009-10-20 09:40:47 -070039#include <plat/control.h>
Tony Lindgren1dbae812005-11-10 14:26:51 +000040
Tony Lindgren15ac7af2009-12-11 16:16:32 -080041#include "mux.h"
Tony Lindgren1dbae812005-11-10 14:26:51 +000042
Mike Rapoport92c9f502009-12-11 16:16:31 -080043#define OMAP_MUX_BASE_OFFSET 0x30 /* Offset from CTRL_BASE */
44#define OMAP_MUX_BASE_SZ 0x5ca
Tony Lindgrend5425be2010-07-05 16:31:35 +030045#define MUXABLE_GPIO_MODE3 BIT(0)
Mike Rapoport92c9f502009-12-11 16:16:31 -080046
Tony Lindgren15ac7af2009-12-11 16:16:32 -080047struct omap_mux_entry {
48 struct omap_mux mux;
49 struct list_head node;
50};
51
Tony Lindgren4b715ef2009-12-11 16:16:32 -080052static unsigned long mux_phys;
Mike Rapoport92c9f502009-12-11 16:16:31 -080053static void __iomem *mux_base;
Tony Lindgrend5425be2010-07-05 16:31:35 +030054static u8 omap_mux_flags;
Mike Rapoport92c9f502009-12-11 16:16:31 -080055
Tony Lindgrend4bb72e2010-01-19 15:15:24 -080056u16 omap_mux_read(u16 reg)
Mike Rapoport92c9f502009-12-11 16:16:31 -080057{
58 if (cpu_is_omap24xx())
59 return __raw_readb(mux_base + reg);
60 else
61 return __raw_readw(mux_base + reg);
62}
63
Tony Lindgrend4bb72e2010-01-19 15:15:24 -080064void omap_mux_write(u16 val, u16 reg)
Mike Rapoport92c9f502009-12-11 16:16:31 -080065{
66 if (cpu_is_omap24xx())
67 __raw_writeb(val, mux_base + reg);
68 else
69 __raw_writew(val, mux_base + reg);
70}
Tony Lindgren7d7f6652008-01-25 00:42:48 -080071
Tony Lindgrend4bb72e2010-01-19 15:15:24 -080072void omap_mux_write_array(struct omap_board_mux *board_mux)
73{
74 while (board_mux->reg_offset != OMAP_MUX_TERMINATOR) {
75 omap_mux_write(board_mux->value, board_mux->reg_offset);
76 board_mux++;
77 }
78}
79
Tony Lindgren15ac7af2009-12-11 16:16:32 -080080static LIST_HEAD(muxmodes);
81static DEFINE_MUTEX(muxmode_mutex);
82
83#ifdef CONFIG_OMAP_MUX
84
85static char *omap_mux_options;
86
87int __init omap_mux_init_gpio(int gpio, int val)
88{
89 struct omap_mux_entry *e;
Sanjeev Premica828762010-09-23 18:27:18 -070090 struct omap_mux *gpio_mux = NULL;
Grazvydas Ignotas8a6f7e12010-08-02 13:18:28 +030091 u16 old_mode;
92 u16 mux_mode;
Tony Lindgren15ac7af2009-12-11 16:16:32 -080093 int found = 0;
94
95 if (!gpio)
96 return -EINVAL;
97
98 list_for_each_entry(e, &muxmodes, node) {
99 struct omap_mux *m = &e->mux;
100 if (gpio == m->gpio) {
Grazvydas Ignotas8a6f7e12010-08-02 13:18:28 +0300101 gpio_mux = m;
Tony Lindgren15ac7af2009-12-11 16:16:32 -0800102 found++;
103 }
104 }
105
Grazvydas Ignotas8a6f7e12010-08-02 13:18:28 +0300106 if (found == 0) {
107 printk(KERN_ERR "mux: Could not set gpio%i\n", gpio);
108 return -ENODEV;
109 }
Tony Lindgren15ac7af2009-12-11 16:16:32 -0800110
111 if (found > 1) {
Grazvydas Ignotas8a6f7e12010-08-02 13:18:28 +0300112 printk(KERN_INFO "mux: Multiple gpio paths (%d) for gpio%i\n",
113 found, gpio);
Tony Lindgren15ac7af2009-12-11 16:16:32 -0800114 return -EINVAL;
115 }
116
Grazvydas Ignotas8a6f7e12010-08-02 13:18:28 +0300117 old_mode = omap_mux_read(gpio_mux->reg_offset);
118 mux_mode = val & ~(OMAP_MUX_NR_MODES - 1);
119 if (omap_mux_flags & MUXABLE_GPIO_MODE3)
120 mux_mode |= OMAP_MUX_MODE3;
121 else
122 mux_mode |= OMAP_MUX_MODE4;
123 printk(KERN_DEBUG "mux: Setting signal %s.gpio%i 0x%04x -> 0x%04x\n",
124 gpio_mux->muxnames[0], gpio, old_mode, mux_mode);
125 omap_mux_write(mux_mode, gpio_mux->reg_offset);
Tony Lindgren15ac7af2009-12-11 16:16:32 -0800126
Grazvydas Ignotas8a6f7e12010-08-02 13:18:28 +0300127 return 0;
Tony Lindgren15ac7af2009-12-11 16:16:32 -0800128}
129
Tony Lindgren5a3b2f72010-10-01 16:35:24 -0700130int __init omap_mux_init_signal(const char *muxname, int val)
Tony Lindgren15ac7af2009-12-11 16:16:32 -0800131{
132 struct omap_mux_entry *e;
Tony Lindgren5a3b2f72010-10-01 16:35:24 -0700133 const char *mode_name;
134 int found = 0, mode0_len = 0;
Tony Lindgren15ac7af2009-12-11 16:16:32 -0800135
136 mode_name = strchr(muxname, '.');
137 if (mode_name) {
Tony Lindgren5a3b2f72010-10-01 16:35:24 -0700138 mode0_len = strlen(muxname) - strlen(mode_name);
Tony Lindgren15ac7af2009-12-11 16:16:32 -0800139 mode_name++;
Tony Lindgren15ac7af2009-12-11 16:16:32 -0800140 } else {
141 mode_name = muxname;
142 }
143
144 list_for_each_entry(e, &muxmodes, node) {
145 struct omap_mux *m = &e->mux;
146 char *m0_entry = m->muxnames[0];
147 int i;
148
Tony Lindgren5a3b2f72010-10-01 16:35:24 -0700149 /* First check for full name in mode0.muxmode format */
150 if (mode0_len && strncmp(muxname, m0_entry, mode0_len))
Tony Lindgren15ac7af2009-12-11 16:16:32 -0800151 continue;
152
Tony Lindgren5a3b2f72010-10-01 16:35:24 -0700153 /* Then check for muxmode only */
Tony Lindgren15ac7af2009-12-11 16:16:32 -0800154 for (i = 0; i < OMAP_MUX_NR_MODES; i++) {
155 char *mode_cur = m->muxnames[i];
156
157 if (!mode_cur)
158 continue;
159
160 if (!strcmp(mode_name, mode_cur)) {
161 u16 old_mode;
162 u16 mux_mode;
163
164 old_mode = omap_mux_read(m->reg_offset);
165 mux_mode = val | i;
166 printk(KERN_DEBUG "mux: Setting signal "
167 "%s.%s 0x%04x -> 0x%04x\n",
168 m0_entry, muxname, old_mode, mux_mode);
169 omap_mux_write(mux_mode, m->reg_offset);
170 found++;
171 }
172 }
173 }
174
175 if (found == 1)
176 return 0;
177
178 if (found > 1) {
179 printk(KERN_ERR "mux: Multiple signal paths (%i) for %s\n",
180 found, muxname);
181 return -EINVAL;
182 }
183
184 printk(KERN_ERR "mux: Could not set signal %s\n", muxname);
185
186 return -ENODEV;
187}
188
Tony Lindgren4b715ef2009-12-11 16:16:32 -0800189#ifdef CONFIG_DEBUG_FS
190
191#define OMAP_MUX_MAX_NR_FLAGS 10
192#define OMAP_MUX_TEST_FLAG(val, mask) \
193 if (((val) & (mask)) == (mask)) { \
194 i++; \
195 flags[i] = #mask; \
196 }
197
198/* REVISIT: Add checking for non-optimal mux settings */
199static inline void omap_mux_decode(struct seq_file *s, u16 val)
200{
201 char *flags[OMAP_MUX_MAX_NR_FLAGS];
Tony Lindgren78737ae2010-02-01 13:03:42 -0800202 char mode[sizeof("OMAP_MUX_MODE") + 1];
Tony Lindgren4b715ef2009-12-11 16:16:32 -0800203 int i = -1;
204
205 sprintf(mode, "OMAP_MUX_MODE%d", val & 0x7);
206 i++;
207 flags[i] = mode;
208
209 OMAP_MUX_TEST_FLAG(val, OMAP_PIN_OFF_WAKEUPENABLE);
210 if (val & OMAP_OFF_EN) {
211 if (!(val & OMAP_OFFOUT_EN)) {
212 if (!(val & OMAP_OFF_PULL_UP)) {
213 OMAP_MUX_TEST_FLAG(val,
214 OMAP_PIN_OFF_INPUT_PULLDOWN);
215 } else {
216 OMAP_MUX_TEST_FLAG(val,
217 OMAP_PIN_OFF_INPUT_PULLUP);
218 }
219 } else {
220 if (!(val & OMAP_OFFOUT_VAL)) {
221 OMAP_MUX_TEST_FLAG(val,
222 OMAP_PIN_OFF_OUTPUT_LOW);
223 } else {
224 OMAP_MUX_TEST_FLAG(val,
225 OMAP_PIN_OFF_OUTPUT_HIGH);
226 }
227 }
228 }
229
230 if (val & OMAP_INPUT_EN) {
231 if (val & OMAP_PULL_ENA) {
232 if (!(val & OMAP_PULL_UP)) {
233 OMAP_MUX_TEST_FLAG(val,
234 OMAP_PIN_INPUT_PULLDOWN);
235 } else {
236 OMAP_MUX_TEST_FLAG(val, OMAP_PIN_INPUT_PULLUP);
237 }
238 } else {
239 OMAP_MUX_TEST_FLAG(val, OMAP_PIN_INPUT);
240 }
241 } else {
242 i++;
243 flags[i] = "OMAP_PIN_OUTPUT";
244 }
245
246 do {
247 seq_printf(s, "%s", flags[i]);
248 if (i > 0)
249 seq_printf(s, " | ");
250 } while (i-- > 0);
251}
252
253#define OMAP_MUX_DEFNAME_LEN 16
254
255static int omap_mux_dbg_board_show(struct seq_file *s, void *unused)
256{
257 struct omap_mux_entry *e;
258
259 list_for_each_entry(e, &muxmodes, node) {
260 struct omap_mux *m = &e->mux;
261 char m0_def[OMAP_MUX_DEFNAME_LEN];
262 char *m0_name = m->muxnames[0];
263 u16 val;
264 int i, mode;
265
266 if (!m0_name)
267 continue;
268
Tony Lindgren78737ae2010-02-01 13:03:42 -0800269 /* REVISIT: Needs to be updated if mode0 names get longer */
Tony Lindgren4b715ef2009-12-11 16:16:32 -0800270 for (i = 0; i < OMAP_MUX_DEFNAME_LEN; i++) {
271 if (m0_name[i] == '\0') {
272 m0_def[i] = m0_name[i];
273 break;
274 }
275 m0_def[i] = toupper(m0_name[i]);
276 }
277 val = omap_mux_read(m->reg_offset);
278 mode = val & OMAP_MUX_MODE7;
279
280 seq_printf(s, "OMAP%i_MUX(%s, ",
281 cpu_is_omap34xx() ? 3 : 0, m0_def);
282 omap_mux_decode(s, val);
283 seq_printf(s, "),\n");
284 }
285
286 return 0;
287}
288
289static int omap_mux_dbg_board_open(struct inode *inode, struct file *file)
290{
291 return single_open(file, omap_mux_dbg_board_show, &inode->i_private);
292}
293
294static const struct file_operations omap_mux_dbg_board_fops = {
295 .open = omap_mux_dbg_board_open,
296 .read = seq_read,
297 .llseek = seq_lseek,
298 .release = single_release,
299};
300
301static int omap_mux_dbg_signal_show(struct seq_file *s, void *unused)
302{
303 struct omap_mux *m = s->private;
304 const char *none = "NA";
305 u16 val;
306 int mode;
307
308 val = omap_mux_read(m->reg_offset);
309 mode = val & OMAP_MUX_MODE7;
310
311 seq_printf(s, "name: %s.%s (0x%08lx/0x%03x = 0x%04x), b %s, t %s\n",
312 m->muxnames[0], m->muxnames[mode],
313 mux_phys + m->reg_offset, m->reg_offset, val,
314 m->balls[0] ? m->balls[0] : none,
315 m->balls[1] ? m->balls[1] : none);
316 seq_printf(s, "mode: ");
317 omap_mux_decode(s, val);
318 seq_printf(s, "\n");
319 seq_printf(s, "signals: %s | %s | %s | %s | %s | %s | %s | %s\n",
320 m->muxnames[0] ? m->muxnames[0] : none,
321 m->muxnames[1] ? m->muxnames[1] : none,
322 m->muxnames[2] ? m->muxnames[2] : none,
323 m->muxnames[3] ? m->muxnames[3] : none,
324 m->muxnames[4] ? m->muxnames[4] : none,
325 m->muxnames[5] ? m->muxnames[5] : none,
326 m->muxnames[6] ? m->muxnames[6] : none,
327 m->muxnames[7] ? m->muxnames[7] : none);
328
329 return 0;
330}
331
332#define OMAP_MUX_MAX_ARG_CHAR 7
333
334static ssize_t omap_mux_dbg_signal_write(struct file *file,
335 const char __user *user_buf,
336 size_t count, loff_t *ppos)
337{
338 char buf[OMAP_MUX_MAX_ARG_CHAR];
339 struct seq_file *seqf;
340 struct omap_mux *m;
341 unsigned long val;
342 int buf_size, ret;
343
344 if (count > OMAP_MUX_MAX_ARG_CHAR)
345 return -EINVAL;
346
347 memset(buf, 0, sizeof(buf));
348 buf_size = min(count, sizeof(buf) - 1);
349
350 if (copy_from_user(buf, user_buf, buf_size))
351 return -EFAULT;
352
353 ret = strict_strtoul(buf, 0x10, &val);
354 if (ret < 0)
355 return ret;
356
357 if (val > 0xffff)
358 return -EINVAL;
359
360 seqf = file->private_data;
361 m = seqf->private;
362
363 omap_mux_write((u16)val, m->reg_offset);
364 *ppos += count;
365
366 return count;
367}
368
369static int omap_mux_dbg_signal_open(struct inode *inode, struct file *file)
370{
371 return single_open(file, omap_mux_dbg_signal_show, inode->i_private);
372}
373
374static const struct file_operations omap_mux_dbg_signal_fops = {
375 .open = omap_mux_dbg_signal_open,
376 .read = seq_read,
377 .write = omap_mux_dbg_signal_write,
378 .llseek = seq_lseek,
379 .release = single_release,
380};
381
382static struct dentry *mux_dbg_dir;
383
384static void __init omap_mux_dbg_init(void)
385{
386 struct omap_mux_entry *e;
387
388 mux_dbg_dir = debugfs_create_dir("omap_mux", NULL);
389 if (!mux_dbg_dir)
390 return;
391
392 (void)debugfs_create_file("board", S_IRUGO, mux_dbg_dir,
393 NULL, &omap_mux_dbg_board_fops);
394
395 list_for_each_entry(e, &muxmodes, node) {
396 struct omap_mux *m = &e->mux;
397
398 (void)debugfs_create_file(m->muxnames[0], S_IWUGO, mux_dbg_dir,
399 m, &omap_mux_dbg_signal_fops);
400 }
401}
402
403#else
404static inline void omap_mux_dbg_init(void)
405{
406}
407#endif /* CONFIG_DEBUG_FS */
408
Tony Lindgren15ac7af2009-12-11 16:16:32 -0800409static void __init omap_mux_free_names(struct omap_mux *m)
410{
411 int i;
412
413 for (i = 0; i < OMAP_MUX_NR_MODES; i++)
414 kfree(m->muxnames[i]);
415
416#ifdef CONFIG_DEBUG_FS
417 for (i = 0; i < OMAP_MUX_NR_SIDES; i++)
418 kfree(m->balls[i]);
Tony Lindgren1dbae812005-11-10 14:26:51 +0000419#endif
Tony Lindgren15ac7af2009-12-11 16:16:32 -0800420
421}
422
423/* Free all data except for GPIO pins unless CONFIG_DEBUG_FS is set */
424static int __init omap_mux_late_init(void)
425{
426 struct omap_mux_entry *e, *tmp;
427
428 list_for_each_entry_safe(e, tmp, &muxmodes, node) {
429 struct omap_mux *m = &e->mux;
430 u16 mode = omap_mux_read(m->reg_offset);
431
432 if (OMAP_MODE_GPIO(mode))
433 continue;
434
435#ifndef CONFIG_DEBUG_FS
436 mutex_lock(&muxmode_mutex);
437 list_del(&e->node);
438 mutex_unlock(&muxmode_mutex);
439 omap_mux_free_names(m);
440 kfree(m);
441#endif
442
443 }
444
Tony Lindgren4b715ef2009-12-11 16:16:32 -0800445 omap_mux_dbg_init();
446
Tony Lindgren15ac7af2009-12-11 16:16:32 -0800447 return 0;
448}
449late_initcall(omap_mux_late_init);
450
451static void __init omap_mux_package_fixup(struct omap_mux *p,
452 struct omap_mux *superset)
453{
454 while (p->reg_offset != OMAP_MUX_TERMINATOR) {
455 struct omap_mux *s = superset;
456 int found = 0;
457
458 while (s->reg_offset != OMAP_MUX_TERMINATOR) {
459 if (s->reg_offset == p->reg_offset) {
460 *s = *p;
461 found++;
462 break;
463 }
464 s++;
465 }
466 if (!found)
467 printk(KERN_ERR "mux: Unknown entry offset 0x%x\n",
468 p->reg_offset);
469 p++;
470 }
471}
472
473#ifdef CONFIG_DEBUG_FS
474
475static void __init omap_mux_package_init_balls(struct omap_ball *b,
476 struct omap_mux *superset)
477{
478 while (b->reg_offset != OMAP_MUX_TERMINATOR) {
479 struct omap_mux *s = superset;
480 int found = 0;
481
482 while (s->reg_offset != OMAP_MUX_TERMINATOR) {
483 if (s->reg_offset == b->reg_offset) {
484 s->balls[0] = b->balls[0];
485 s->balls[1] = b->balls[1];
486 found++;
487 break;
488 }
489 s++;
490 }
491 if (!found)
492 printk(KERN_ERR "mux: Unknown ball offset 0x%x\n",
493 b->reg_offset);
494 b++;
495 }
496}
497
498#else /* CONFIG_DEBUG_FS */
499
500static inline void omap_mux_package_init_balls(struct omap_ball *b,
501 struct omap_mux *superset)
502{
503}
504
505#endif /* CONFIG_DEBUG_FS */
506
507static int __init omap_mux_setup(char *options)
508{
509 if (!options)
510 return 0;
511
512 omap_mux_options = options;
513
514 return 1;
515}
516__setup("omap_mux=", omap_mux_setup);
517
518/*
519 * Note that the omap_mux=some.signal1=0x1234,some.signal2=0x1234
520 * cmdline options only override the bootloader values.
521 * During development, please enable CONFIG_DEBUG_FS, and use the
522 * signal specific entries under debugfs.
523 */
524static void __init omap_mux_set_cmdline_signals(void)
525{
526 char *options, *next_opt, *token;
527
528 if (!omap_mux_options)
529 return;
530
531 options = kmalloc(strlen(omap_mux_options) + 1, GFP_KERNEL);
532 if (!options)
533 return;
534
535 strcpy(options, omap_mux_options);
536 next_opt = options;
537
538 while ((token = strsep(&next_opt, ",")) != NULL) {
539 char *keyval, *name;
540 unsigned long val;
541
542 keyval = token;
543 name = strsep(&keyval, "=");
544 if (name) {
545 int res;
546
547 res = strict_strtoul(keyval, 0x10, &val);
548 if (res < 0)
549 continue;
550
551 omap_mux_init_signal(name, (u16)val);
552 }
553 }
554
555 kfree(options);
556}
557
Tony Lindgren15ac7af2009-12-11 16:16:32 -0800558static int __init omap_mux_copy_names(struct omap_mux *src,
559 struct omap_mux *dst)
560{
561 int i;
562
563 for (i = 0; i < OMAP_MUX_NR_MODES; i++) {
564 if (src->muxnames[i]) {
565 dst->muxnames[i] =
566 kmalloc(strlen(src->muxnames[i]) + 1,
567 GFP_KERNEL);
568 if (!dst->muxnames[i])
569 goto free;
570 strcpy(dst->muxnames[i], src->muxnames[i]);
571 }
572 }
573
574#ifdef CONFIG_DEBUG_FS
575 for (i = 0; i < OMAP_MUX_NR_SIDES; i++) {
576 if (src->balls[i]) {
577 dst->balls[i] =
578 kmalloc(strlen(src->balls[i]) + 1,
579 GFP_KERNEL);
580 if (!dst->balls[i])
581 goto free;
582 strcpy(dst->balls[i], src->balls[i]);
583 }
584 }
585#endif
586
587 return 0;
588
589free:
590 omap_mux_free_names(dst);
591 return -ENOMEM;
592
593}
594
595#endif /* CONFIG_OMAP_MUX */
596
597static u16 omap_mux_get_by_gpio(int gpio)
598{
599 struct omap_mux_entry *e;
600 u16 offset = OMAP_MUX_TERMINATOR;
601
602 list_for_each_entry(e, &muxmodes, node) {
603 struct omap_mux *m = &e->mux;
604 if (m->gpio == gpio) {
605 offset = m->reg_offset;
606 break;
607 }
608 }
609
610 return offset;
611}
612
613/* Needed for dynamic muxing of GPIO pins for off-idle */
614u16 omap_mux_get_gpio(int gpio)
615{
616 u16 offset;
617
618 offset = omap_mux_get_by_gpio(gpio);
619 if (offset == OMAP_MUX_TERMINATOR) {
620 printk(KERN_ERR "mux: Could not get gpio%i\n", gpio);
621 return offset;
622 }
623
624 return omap_mux_read(offset);
625}
626
627/* Needed for dynamic muxing of GPIO pins for off-idle */
628void omap_mux_set_gpio(u16 val, int gpio)
629{
630 u16 offset;
631
632 offset = omap_mux_get_by_gpio(gpio);
633 if (offset == OMAP_MUX_TERMINATOR) {
634 printk(KERN_ERR "mux: Could not set gpio%i\n", gpio);
635 return;
636 }
637
638 omap_mux_write(val, offset);
639}
640
641static struct omap_mux * __init omap_mux_list_add(struct omap_mux *src)
642{
643 struct omap_mux_entry *entry;
644 struct omap_mux *m;
645
646 entry = kzalloc(sizeof(struct omap_mux_entry), GFP_KERNEL);
647 if (!entry)
648 return NULL;
649
650 m = &entry->mux;
651 memcpy(m, src, sizeof(struct omap_mux_entry));
652
653#ifdef CONFIG_OMAP_MUX
654 if (omap_mux_copy_names(src, m)) {
655 kfree(entry);
656 return NULL;
657 }
658#endif
659
660 mutex_lock(&muxmode_mutex);
661 list_add_tail(&entry->node, &muxmodes);
662 mutex_unlock(&muxmode_mutex);
663
664 return m;
665}
666
667/*
668 * Note if CONFIG_OMAP_MUX is not selected, we will only initialize
669 * the GPIO to mux offset mapping that is needed for dynamic muxing
670 * of GPIO pins for off-idle.
671 */
672static void __init omap_mux_init_list(struct omap_mux *superset)
673{
674 while (superset->reg_offset != OMAP_MUX_TERMINATOR) {
675 struct omap_mux *entry;
676
Ranjith Lohithakshanb72c7d52010-02-17 17:17:01 +0000677#ifdef CONFIG_OMAP_MUX
678 if (!superset->muxnames || !superset->muxnames[0]) {
Tony Lindgren15ac7af2009-12-11 16:16:32 -0800679 superset++;
680 continue;
681 }
Ranjith Lohithakshanb72c7d52010-02-17 17:17:01 +0000682#else
683 /* Skip pins that are not muxed as GPIO by bootloader */
684 if (!OMAP_MODE_GPIO(omap_mux_read(superset->reg_offset))) {
Tony Lindgren9ecef432010-02-01 11:22:54 -0800685 superset++;
686 continue;
687 }
688#endif
689
Tony Lindgren15ac7af2009-12-11 16:16:32 -0800690 entry = omap_mux_list_add(superset);
691 if (!entry) {
692 printk(KERN_ERR "mux: Could not add entry\n");
693 return;
694 }
695 superset++;
696 }
697}
698
Tony Lindgren321cfc82010-02-15 10:03:35 -0800699#ifdef CONFIG_OMAP_MUX
700
701static void omap_mux_init_package(struct omap_mux *superset,
702 struct omap_mux *package_subset,
703 struct omap_ball *package_balls)
704{
705 if (package_subset)
706 omap_mux_package_fixup(package_subset, superset);
707 if (package_balls)
708 omap_mux_package_init_balls(package_balls, superset);
709}
710
711static void omap_mux_init_signals(struct omap_board_mux *board_mux)
712{
713 omap_mux_set_cmdline_signals();
714 omap_mux_write_array(board_mux);
715}
716
717#else
718
719static void omap_mux_init_package(struct omap_mux *superset,
720 struct omap_mux *package_subset,
721 struct omap_ball *package_balls)
722{
723}
724
725static void omap_mux_init_signals(struct omap_board_mux *board_mux)
726{
727}
728
729#endif
730
Tony Lindgren15ac7af2009-12-11 16:16:32 -0800731int __init omap_mux_init(u32 mux_pbase, u32 mux_size,
732 struct omap_mux *superset,
733 struct omap_mux *package_subset,
734 struct omap_board_mux *board_mux,
735 struct omap_ball *package_balls)
736{
737 if (mux_base)
738 return -EBUSY;
739
Tony Lindgren4b715ef2009-12-11 16:16:32 -0800740 mux_phys = mux_pbase;
Tony Lindgren15ac7af2009-12-11 16:16:32 -0800741 mux_base = ioremap(mux_pbase, mux_size);
742 if (!mux_base) {
743 printk(KERN_ERR "mux: Could not ioremap\n");
744 return -ENODEV;
745 }
746
Tony Lindgrend5425be2010-07-05 16:31:35 +0300747 if (cpu_is_omap24xx())
748 omap_mux_flags = MUXABLE_GPIO_MODE3;
749
Tony Lindgren321cfc82010-02-15 10:03:35 -0800750 omap_mux_init_package(superset, package_subset, package_balls);
Tony Lindgren15ac7af2009-12-11 16:16:32 -0800751 omap_mux_init_list(superset);
Tony Lindgren321cfc82010-02-15 10:03:35 -0800752 omap_mux_init_signals(board_mux);
Tony Lindgren2cb0c542010-01-19 18:17:07 -0800753
Tony Lindgren15ac7af2009-12-11 16:16:32 -0800754 return 0;
755}
756