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