• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/components/opensource/linux/linux-2.6.36/arch/arm/mach-omap2/
1/*
2 * linux/arch/arm/mach-omap2/mux.c
3 *
4 * OMAP2 and OMAP3 pin multiplexing configurations
5 *
6 * Copyright (C) 2004 - 2008 Texas Instruments Inc.
7 * Copyright (C) 2003 - 2008 Nokia Corporation
8 *
9 * Written by Tony Lindgren
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 */
26#include <linux/module.h>
27#include <linux/init.h>
28#include <linux/io.h>
29#include <linux/slab.h>
30#include <linux/spinlock.h>
31#include <linux/list.h>
32#include <linux/ctype.h>
33#include <linux/debugfs.h>
34#include <linux/seq_file.h>
35#include <linux/uaccess.h>
36
37#include <asm/system.h>
38
39#include <plat/control.h>
40
41#include "mux.h"
42
43#define OMAP_MUX_BASE_OFFSET		0x30	/* Offset from CTRL_BASE */
44#define OMAP_MUX_BASE_SZ		0x5ca
45#define MUXABLE_GPIO_MODE3		BIT(0)
46
47struct omap_mux_entry {
48	struct omap_mux		mux;
49	struct list_head	node;
50};
51
52static unsigned long mux_phys;
53static void __iomem *mux_base;
54static u8 omap_mux_flags;
55
56u16 omap_mux_read(u16 reg)
57{
58	if (cpu_is_omap24xx())
59		return __raw_readb(mux_base + reg);
60	else
61		return __raw_readw(mux_base + reg);
62}
63
64void omap_mux_write(u16 val, u16 reg)
65{
66	if (cpu_is_omap24xx())
67		__raw_writeb(val, mux_base + reg);
68	else
69		__raw_writew(val, mux_base + reg);
70}
71
72void 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
80static 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;
90	struct omap_mux *gpio_mux;
91	u16 old_mode;
92	u16 mux_mode;
93	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) {
101			gpio_mux = m;
102			found++;
103		}
104	}
105
106	if (found == 0) {
107		printk(KERN_ERR "mux: Could not set gpio%i\n", gpio);
108		return -ENODEV;
109	}
110
111	if (found > 1) {
112		printk(KERN_INFO "mux: Multiple gpio paths (%d) for gpio%i\n",
113				found, gpio);
114		return -EINVAL;
115	}
116
117	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);
126
127	return 0;
128}
129
130int __init omap_mux_init_signal(char *muxname, int val)
131{
132	struct omap_mux_entry *e;
133	char *m0_name = NULL, *mode_name = NULL;
134	int found = 0;
135
136	mode_name = strchr(muxname, '.');
137	if (mode_name) {
138		*mode_name = '\0';
139		mode_name++;
140		m0_name = muxname;
141	} else {
142		mode_name = muxname;
143	}
144
145	list_for_each_entry(e, &muxmodes, node) {
146		struct omap_mux *m = &e->mux;
147		char *m0_entry = m->muxnames[0];
148		int i;
149
150		if (m0_name && strcmp(m0_name, m0_entry))
151			continue;
152
153		for (i = 0; i < OMAP_MUX_NR_MODES; i++) {
154			char *mode_cur = m->muxnames[i];
155
156			if (!mode_cur)
157				continue;
158
159			if (!strcmp(mode_name, mode_cur)) {
160				u16 old_mode;
161				u16 mux_mode;
162
163				old_mode = omap_mux_read(m->reg_offset);
164				mux_mode = val | i;
165				printk(KERN_DEBUG "mux: Setting signal "
166					"%s.%s 0x%04x -> 0x%04x\n",
167					m0_entry, muxname, old_mode, mux_mode);
168				omap_mux_write(mux_mode, m->reg_offset);
169				found++;
170			}
171		}
172	}
173
174	if (found == 1)
175		return 0;
176
177	if (found > 1) {
178		printk(KERN_ERR "mux: Multiple signal paths (%i) for %s\n",
179				found, muxname);
180		return -EINVAL;
181	}
182
183	printk(KERN_ERR "mux: Could not set signal %s\n", muxname);
184
185	return -ENODEV;
186}
187
188#ifdef CONFIG_DEBUG_FS
189
190#define OMAP_MUX_MAX_NR_FLAGS	10
191#define OMAP_MUX_TEST_FLAG(val, mask)				\
192	if (((val) & (mask)) == (mask)) {			\
193		i++;						\
194		flags[i] =  #mask;				\
195	}
196
197/* REVISIT: Add checking for non-optimal mux settings */
198static inline void omap_mux_decode(struct seq_file *s, u16 val)
199{
200	char *flags[OMAP_MUX_MAX_NR_FLAGS];
201	char mode[sizeof("OMAP_MUX_MODE") + 1];
202	int i = -1;
203
204	sprintf(mode, "OMAP_MUX_MODE%d", val & 0x7);
205	i++;
206	flags[i] = mode;
207
208	OMAP_MUX_TEST_FLAG(val, OMAP_PIN_OFF_WAKEUPENABLE);
209	if (val & OMAP_OFF_EN) {
210		if (!(val & OMAP_OFFOUT_EN)) {
211			if (!(val & OMAP_OFF_PULL_UP)) {
212				OMAP_MUX_TEST_FLAG(val,
213					OMAP_PIN_OFF_INPUT_PULLDOWN);
214			} else {
215				OMAP_MUX_TEST_FLAG(val,
216					OMAP_PIN_OFF_INPUT_PULLUP);
217			}
218		} else {
219			if (!(val & OMAP_OFFOUT_VAL)) {
220				OMAP_MUX_TEST_FLAG(val,
221					OMAP_PIN_OFF_OUTPUT_LOW);
222			} else {
223				OMAP_MUX_TEST_FLAG(val,
224					OMAP_PIN_OFF_OUTPUT_HIGH);
225			}
226		}
227	}
228
229	if (val & OMAP_INPUT_EN) {
230		if (val & OMAP_PULL_ENA) {
231			if (!(val & OMAP_PULL_UP)) {
232				OMAP_MUX_TEST_FLAG(val,
233					OMAP_PIN_INPUT_PULLDOWN);
234			} else {
235				OMAP_MUX_TEST_FLAG(val, OMAP_PIN_INPUT_PULLUP);
236			}
237		} else {
238			OMAP_MUX_TEST_FLAG(val, OMAP_PIN_INPUT);
239		}
240	} else {
241		i++;
242		flags[i] = "OMAP_PIN_OUTPUT";
243	}
244
245	do {
246		seq_printf(s, "%s", flags[i]);
247		if (i > 0)
248			seq_printf(s, " | ");
249	} while (i-- > 0);
250}
251
252#define OMAP_MUX_DEFNAME_LEN	16
253
254static int omap_mux_dbg_board_show(struct seq_file *s, void *unused)
255{
256	struct omap_mux_entry *e;
257
258	list_for_each_entry(e, &muxmodes, node) {
259		struct omap_mux *m = &e->mux;
260		char m0_def[OMAP_MUX_DEFNAME_LEN];
261		char *m0_name = m->muxnames[0];
262		u16 val;
263		int i, mode;
264
265		if (!m0_name)
266			continue;
267
268		/* REVISIT: Needs to be updated if mode0 names get longer */
269		for (i = 0; i < OMAP_MUX_DEFNAME_LEN; i++) {
270			if (m0_name[i] == '\0') {
271				m0_def[i] = m0_name[i];
272				break;
273			}
274			m0_def[i] = toupper(m0_name[i]);
275		}
276		val = omap_mux_read(m->reg_offset);
277		mode = val & OMAP_MUX_MODE7;
278
279		seq_printf(s, "OMAP%i_MUX(%s, ",
280					cpu_is_omap34xx() ? 3 : 0, m0_def);
281		omap_mux_decode(s, val);
282		seq_printf(s, "),\n");
283	}
284
285	return 0;
286}
287
288static int omap_mux_dbg_board_open(struct inode *inode, struct file *file)
289{
290	return single_open(file, omap_mux_dbg_board_show, &inode->i_private);
291}
292
293static const struct file_operations omap_mux_dbg_board_fops = {
294	.open		= omap_mux_dbg_board_open,
295	.read		= seq_read,
296	.llseek		= seq_lseek,
297	.release	= single_release,
298};
299
300static int omap_mux_dbg_signal_show(struct seq_file *s, void *unused)
301{
302	struct omap_mux *m = s->private;
303	const char *none = "NA";
304	u16 val;
305	int mode;
306
307	val = omap_mux_read(m->reg_offset);
308	mode = val & OMAP_MUX_MODE7;
309
310	seq_printf(s, "name: %s.%s (0x%08lx/0x%03x = 0x%04x), b %s, t %s\n",
311			m->muxnames[0], m->muxnames[mode],
312			mux_phys + m->reg_offset, m->reg_offset, val,
313			m->balls[0] ? m->balls[0] : none,
314			m->balls[1] ? m->balls[1] : none);
315	seq_printf(s, "mode: ");
316	omap_mux_decode(s, val);
317	seq_printf(s, "\n");
318	seq_printf(s, "signals: %s | %s | %s | %s | %s | %s | %s | %s\n",
319			m->muxnames[0] ? m->muxnames[0] : none,
320			m->muxnames[1] ? m->muxnames[1] : none,
321			m->muxnames[2] ? m->muxnames[2] : none,
322			m->muxnames[3] ? m->muxnames[3] : none,
323			m->muxnames[4] ? m->muxnames[4] : none,
324			m->muxnames[5] ? m->muxnames[5] : none,
325			m->muxnames[6] ? m->muxnames[6] : none,
326			m->muxnames[7] ? m->muxnames[7] : none);
327
328	return 0;
329}
330
331#define OMAP_MUX_MAX_ARG_CHAR  7
332
333static ssize_t omap_mux_dbg_signal_write(struct file *file,
334						const char __user *user_buf,
335						size_t count, loff_t *ppos)
336{
337	char buf[OMAP_MUX_MAX_ARG_CHAR];
338	struct seq_file *seqf;
339	struct omap_mux *m;
340	unsigned long val;
341	int buf_size, ret;
342
343	if (count > OMAP_MUX_MAX_ARG_CHAR)
344		return -EINVAL;
345
346	memset(buf, 0, sizeof(buf));
347	buf_size = min(count, sizeof(buf) - 1);
348
349	if (copy_from_user(buf, user_buf, buf_size))
350		return -EFAULT;
351
352	ret = strict_strtoul(buf, 0x10, &val);
353	if (ret < 0)
354		return ret;
355
356	if (val > 0xffff)
357		return -EINVAL;
358
359	seqf = file->private_data;
360	m = seqf->private;
361
362	omap_mux_write((u16)val, m->reg_offset);
363	*ppos += count;
364
365	return count;
366}
367
368static int omap_mux_dbg_signal_open(struct inode *inode, struct file *file)
369{
370	return single_open(file, omap_mux_dbg_signal_show, inode->i_private);
371}
372
373static const struct file_operations omap_mux_dbg_signal_fops = {
374	.open		= omap_mux_dbg_signal_open,
375	.read		= seq_read,
376	.write		= omap_mux_dbg_signal_write,
377	.llseek		= seq_lseek,
378	.release	= single_release,
379};
380
381static struct dentry *mux_dbg_dir;
382
383static void __init omap_mux_dbg_init(void)
384{
385	struct omap_mux_entry *e;
386
387	mux_dbg_dir = debugfs_create_dir("omap_mux", NULL);
388	if (!mux_dbg_dir)
389		return;
390
391	(void)debugfs_create_file("board", S_IRUGO, mux_dbg_dir,
392					NULL, &omap_mux_dbg_board_fops);
393
394	list_for_each_entry(e, &muxmodes, node) {
395		struct omap_mux *m = &e->mux;
396
397		(void)debugfs_create_file(m->muxnames[0], S_IWUGO, mux_dbg_dir,
398					m, &omap_mux_dbg_signal_fops);
399	}
400}
401
402#else
403static inline void omap_mux_dbg_init(void)
404{
405}
406#endif	/* CONFIG_DEBUG_FS */
407
408static void __init omap_mux_free_names(struct omap_mux *m)
409{
410	int i;
411
412	for (i = 0; i < OMAP_MUX_NR_MODES; i++)
413		kfree(m->muxnames[i]);
414
415#ifdef CONFIG_DEBUG_FS
416	for (i = 0; i < OMAP_MUX_NR_SIDES; i++)
417		kfree(m->balls[i]);
418#endif
419
420}
421
422/* Free all data except for GPIO pins unless CONFIG_DEBUG_FS is set */
423static int __init omap_mux_late_init(void)
424{
425	struct omap_mux_entry *e, *tmp;
426
427	list_for_each_entry_safe(e, tmp, &muxmodes, node) {
428		struct omap_mux *m = &e->mux;
429		u16 mode = omap_mux_read(m->reg_offset);
430
431		if (OMAP_MODE_GPIO(mode))
432			continue;
433
434#ifndef CONFIG_DEBUG_FS
435		mutex_lock(&muxmode_mutex);
436		list_del(&e->node);
437		mutex_unlock(&muxmode_mutex);
438		omap_mux_free_names(m);
439		kfree(m);
440#endif
441
442	}
443
444	omap_mux_dbg_init();
445
446	return 0;
447}
448late_initcall(omap_mux_late_init);
449
450static void __init omap_mux_package_fixup(struct omap_mux *p,
451					struct omap_mux *superset)
452{
453	while (p->reg_offset !=  OMAP_MUX_TERMINATOR) {
454		struct omap_mux *s = superset;
455		int found = 0;
456
457		while (s->reg_offset != OMAP_MUX_TERMINATOR) {
458			if (s->reg_offset == p->reg_offset) {
459				*s = *p;
460				found++;
461				break;
462			}
463			s++;
464		}
465		if (!found)
466			printk(KERN_ERR "mux: Unknown entry offset 0x%x\n",
467					p->reg_offset);
468		p++;
469	}
470}
471
472#ifdef CONFIG_DEBUG_FS
473
474static void __init omap_mux_package_init_balls(struct omap_ball *b,
475				struct omap_mux *superset)
476{
477	while (b->reg_offset != OMAP_MUX_TERMINATOR) {
478		struct omap_mux *s = superset;
479		int found = 0;
480
481		while (s->reg_offset != OMAP_MUX_TERMINATOR) {
482			if (s->reg_offset == b->reg_offset) {
483				s->balls[0] = b->balls[0];
484				s->balls[1] = b->balls[1];
485				found++;
486				break;
487			}
488			s++;
489		}
490		if (!found)
491			printk(KERN_ERR "mux: Unknown ball offset 0x%x\n",
492					b->reg_offset);
493		b++;
494	}
495}
496
497#else	/* CONFIG_DEBUG_FS */
498
499static inline void omap_mux_package_init_balls(struct omap_ball *b,
500					struct omap_mux *superset)
501{
502}
503
504#endif	/* CONFIG_DEBUG_FS */
505
506static int __init omap_mux_setup(char *options)
507{
508	if (!options)
509		return 0;
510
511	omap_mux_options = options;
512
513	return 1;
514}
515__setup("omap_mux=", omap_mux_setup);
516
517/*
518 * Note that the omap_mux=some.signal1=0x1234,some.signal2=0x1234
519 * cmdline options only override the bootloader values.
520 * During development, please enable CONFIG_DEBUG_FS, and use the
521 * signal specific entries under debugfs.
522 */
523static void __init omap_mux_set_cmdline_signals(void)
524{
525	char *options, *next_opt, *token;
526
527	if (!omap_mux_options)
528		return;
529
530	options = kmalloc(strlen(omap_mux_options) + 1, GFP_KERNEL);
531	if (!options)
532		return;
533
534	strcpy(options, omap_mux_options);
535	next_opt = options;
536
537	while ((token = strsep(&next_opt, ",")) != NULL) {
538		char *keyval, *name;
539		unsigned long val;
540
541		keyval = token;
542		name = strsep(&keyval, "=");
543		if (name) {
544			int res;
545
546			res = strict_strtoul(keyval, 0x10, &val);
547			if (res < 0)
548				continue;
549
550			omap_mux_init_signal(name, (u16)val);
551		}
552	}
553
554	kfree(options);
555}
556
557static int __init omap_mux_copy_names(struct omap_mux *src,
558					struct omap_mux *dst)
559{
560	int i;
561
562	for (i = 0; i < OMAP_MUX_NR_MODES; i++) {
563		if (src->muxnames[i]) {
564			dst->muxnames[i] =
565				kmalloc(strlen(src->muxnames[i]) + 1,
566					GFP_KERNEL);
567			if (!dst->muxnames[i])
568				goto free;
569			strcpy(dst->muxnames[i], src->muxnames[i]);
570		}
571	}
572
573#ifdef CONFIG_DEBUG_FS
574	for (i = 0; i < OMAP_MUX_NR_SIDES; i++) {
575		if (src->balls[i]) {
576			dst->balls[i] =
577				kmalloc(strlen(src->balls[i]) + 1,
578					GFP_KERNEL);
579			if (!dst->balls[i])
580				goto free;
581			strcpy(dst->balls[i], src->balls[i]);
582		}
583	}
584#endif
585
586	return 0;
587
588free:
589	omap_mux_free_names(dst);
590	return -ENOMEM;
591
592}
593
594#endif	/* CONFIG_OMAP_MUX */
595
596static u16 omap_mux_get_by_gpio(int gpio)
597{
598	struct omap_mux_entry *e;
599	u16 offset = OMAP_MUX_TERMINATOR;
600
601	list_for_each_entry(e, &muxmodes, node) {
602		struct omap_mux *m = &e->mux;
603		if (m->gpio == gpio) {
604			offset = m->reg_offset;
605			break;
606		}
607	}
608
609	return offset;
610}
611
612/* Needed for dynamic muxing of GPIO pins for off-idle */
613u16 omap_mux_get_gpio(int gpio)
614{
615	u16 offset;
616
617	offset = omap_mux_get_by_gpio(gpio);
618	if (offset == OMAP_MUX_TERMINATOR) {
619		printk(KERN_ERR "mux: Could not get gpio%i\n", gpio);
620		return offset;
621	}
622
623	return omap_mux_read(offset);
624}
625
626/* Needed for dynamic muxing of GPIO pins for off-idle */
627void omap_mux_set_gpio(u16 val, int gpio)
628{
629	u16 offset;
630
631	offset = omap_mux_get_by_gpio(gpio);
632	if (offset == OMAP_MUX_TERMINATOR) {
633		printk(KERN_ERR "mux: Could not set gpio%i\n", gpio);
634		return;
635	}
636
637	omap_mux_write(val, offset);
638}
639
640static struct omap_mux * __init omap_mux_list_add(struct omap_mux *src)
641{
642	struct omap_mux_entry *entry;
643	struct omap_mux *m;
644
645	entry = kzalloc(sizeof(struct omap_mux_entry), GFP_KERNEL);
646	if (!entry)
647		return NULL;
648
649	m = &entry->mux;
650	memcpy(m, src, sizeof(struct omap_mux_entry));
651
652#ifdef CONFIG_OMAP_MUX
653	if (omap_mux_copy_names(src, m)) {
654		kfree(entry);
655		return NULL;
656	}
657#endif
658
659	mutex_lock(&muxmode_mutex);
660	list_add_tail(&entry->node, &muxmodes);
661	mutex_unlock(&muxmode_mutex);
662
663	return m;
664}
665
666/*
667 * Note if CONFIG_OMAP_MUX is not selected, we will only initialize
668 * the GPIO to mux offset mapping that is needed for dynamic muxing
669 * of GPIO pins for off-idle.
670 */
671static void __init omap_mux_init_list(struct omap_mux *superset)
672{
673	while (superset->reg_offset !=  OMAP_MUX_TERMINATOR) {
674		struct omap_mux *entry;
675
676#ifdef CONFIG_OMAP_MUX
677		if (!superset->muxnames || !superset->muxnames[0]) {
678			superset++;
679			continue;
680		}
681#else
682		/* Skip pins that are not muxed as GPIO by bootloader */
683		if (!OMAP_MODE_GPIO(omap_mux_read(superset->reg_offset))) {
684			superset++;
685			continue;
686		}
687#endif
688
689		entry = omap_mux_list_add(superset);
690		if (!entry) {
691			printk(KERN_ERR "mux: Could not add entry\n");
692			return;
693		}
694		superset++;
695	}
696}
697
698#ifdef CONFIG_OMAP_MUX
699
700static void omap_mux_init_package(struct omap_mux *superset,
701				  struct omap_mux *package_subset,
702				  struct omap_ball *package_balls)
703{
704	if (package_subset)
705		omap_mux_package_fixup(package_subset, superset);
706	if (package_balls)
707		omap_mux_package_init_balls(package_balls, superset);
708}
709
710static void omap_mux_init_signals(struct omap_board_mux *board_mux)
711{
712	omap_mux_set_cmdline_signals();
713	omap_mux_write_array(board_mux);
714}
715
716#else
717
718static void omap_mux_init_package(struct omap_mux *superset,
719				  struct omap_mux *package_subset,
720				  struct omap_ball *package_balls)
721{
722}
723
724static void omap_mux_init_signals(struct omap_board_mux *board_mux)
725{
726}
727
728#endif
729
730int __init omap_mux_init(u32 mux_pbase, u32 mux_size,
731				struct omap_mux *superset,
732				struct omap_mux *package_subset,
733				struct omap_board_mux *board_mux,
734				struct omap_ball *package_balls)
735{
736	if (mux_base)
737		return -EBUSY;
738
739	mux_phys = mux_pbase;
740	mux_base = ioremap(mux_pbase, mux_size);
741	if (!mux_base) {
742		printk(KERN_ERR "mux: Could not ioremap\n");
743		return -ENODEV;
744	}
745
746	if (cpu_is_omap24xx())
747		omap_mux_flags = MUXABLE_GPIO_MODE3;
748
749	omap_mux_init_package(superset, package_subset, package_balls);
750	omap_mux_init_list(superset);
751	omap_mux_init_signals(board_mux);
752
753	return 0;
754}
755