diff options
author | Tony Lindgren <tony@atomide.com> | 2009-12-11 19:16:32 -0500 |
---|---|---|
committer | Tony Lindgren <tony@atomide.com> | 2009-12-11 19:16:32 -0500 |
commit | 4b715efccf9547c0d7fe864277526fee3d9b6bba (patch) | |
tree | 346705cf6fcb8a8259c7f77e2419ed6068eb60b3 /arch/arm | |
parent | ca5742bdb58ebb74499731855dccf8f8a858b2e4 (diff) |
omap: mux: Add debugfs support for new mux code
Add debugfs support for new mux code
Signed-off-by: Tony Lindgren <tony@atomide.com>
Diffstat (limited to 'arch/arm')
-rw-r--r-- | arch/arm/mach-omap2/mux.c | 227 |
1 files changed, 227 insertions, 0 deletions
diff --git a/arch/arm/mach-omap2/mux.c b/arch/arm/mach-omap2/mux.c index b082b504de8b..d9684331e080 100644 --- a/arch/arm/mach-omap2/mux.c +++ b/arch/arm/mach-omap2/mux.c | |||
@@ -28,6 +28,10 @@ | |||
28 | #include <linux/io.h> | 28 | #include <linux/io.h> |
29 | #include <linux/spinlock.h> | 29 | #include <linux/spinlock.h> |
30 | #include <linux/list.h> | 30 | #include <linux/list.h> |
31 | #include <linux/ctype.h> | ||
32 | #include <linux/debugfs.h> | ||
33 | #include <linux/seq_file.h> | ||
34 | #include <linux/uaccess.h> | ||
31 | 35 | ||
32 | #include <asm/system.h> | 36 | #include <asm/system.h> |
33 | 37 | ||
@@ -44,6 +48,7 @@ struct omap_mux_entry { | |||
44 | struct list_head node; | 48 | struct list_head node; |
45 | }; | 49 | }; |
46 | 50 | ||
51 | static unsigned long mux_phys; | ||
47 | static void __iomem *mux_base; | 52 | static void __iomem *mux_base; |
48 | 53 | ||
49 | static inline u16 omap_mux_read(u16 reg) | 54 | static inline u16 omap_mux_read(u16 reg) |
@@ -807,6 +812,225 @@ int __init omap_mux_init_signal(char *muxname, int val) | |||
807 | return -ENODEV; | 812 | return -ENODEV; |
808 | } | 813 | } |
809 | 814 | ||
815 | #ifdef CONFIG_DEBUG_FS | ||
816 | |||
817 | #define OMAP_MUX_MAX_NR_FLAGS 10 | ||
818 | #define OMAP_MUX_TEST_FLAG(val, mask) \ | ||
819 | if (((val) & (mask)) == (mask)) { \ | ||
820 | i++; \ | ||
821 | flags[i] = #mask; \ | ||
822 | } | ||
823 | |||
824 | /* REVISIT: Add checking for non-optimal mux settings */ | ||
825 | static inline void omap_mux_decode(struct seq_file *s, u16 val) | ||
826 | { | ||
827 | char *flags[OMAP_MUX_MAX_NR_FLAGS]; | ||
828 | char mode[14]; | ||
829 | int i = -1; | ||
830 | |||
831 | sprintf(mode, "OMAP_MUX_MODE%d", val & 0x7); | ||
832 | i++; | ||
833 | flags[i] = mode; | ||
834 | |||
835 | OMAP_MUX_TEST_FLAG(val, OMAP_PIN_OFF_WAKEUPENABLE); | ||
836 | if (val & OMAP_OFF_EN) { | ||
837 | if (!(val & OMAP_OFFOUT_EN)) { | ||
838 | if (!(val & OMAP_OFF_PULL_UP)) { | ||
839 | OMAP_MUX_TEST_FLAG(val, | ||
840 | OMAP_PIN_OFF_INPUT_PULLDOWN); | ||
841 | } else { | ||
842 | OMAP_MUX_TEST_FLAG(val, | ||
843 | OMAP_PIN_OFF_INPUT_PULLUP); | ||
844 | } | ||
845 | } else { | ||
846 | if (!(val & OMAP_OFFOUT_VAL)) { | ||
847 | OMAP_MUX_TEST_FLAG(val, | ||
848 | OMAP_PIN_OFF_OUTPUT_LOW); | ||
849 | } else { | ||
850 | OMAP_MUX_TEST_FLAG(val, | ||
851 | OMAP_PIN_OFF_OUTPUT_HIGH); | ||
852 | } | ||
853 | } | ||
854 | } | ||
855 | |||
856 | if (val & OMAP_INPUT_EN) { | ||
857 | if (val & OMAP_PULL_ENA) { | ||
858 | if (!(val & OMAP_PULL_UP)) { | ||
859 | OMAP_MUX_TEST_FLAG(val, | ||
860 | OMAP_PIN_INPUT_PULLDOWN); | ||
861 | } else { | ||
862 | OMAP_MUX_TEST_FLAG(val, OMAP_PIN_INPUT_PULLUP); | ||
863 | } | ||
864 | } else { | ||
865 | OMAP_MUX_TEST_FLAG(val, OMAP_PIN_INPUT); | ||
866 | } | ||
867 | } else { | ||
868 | i++; | ||
869 | flags[i] = "OMAP_PIN_OUTPUT"; | ||
870 | } | ||
871 | |||
872 | do { | ||
873 | seq_printf(s, "%s", flags[i]); | ||
874 | if (i > 0) | ||
875 | seq_printf(s, " | "); | ||
876 | } while (i-- > 0); | ||
877 | } | ||
878 | |||
879 | #define OMAP_MUX_DEFNAME_LEN 16 | ||
880 | |||
881 | static int omap_mux_dbg_board_show(struct seq_file *s, void *unused) | ||
882 | { | ||
883 | struct omap_mux_entry *e; | ||
884 | |||
885 | list_for_each_entry(e, &muxmodes, node) { | ||
886 | struct omap_mux *m = &e->mux; | ||
887 | char m0_def[OMAP_MUX_DEFNAME_LEN]; | ||
888 | char *m0_name = m->muxnames[0]; | ||
889 | u16 val; | ||
890 | int i, mode; | ||
891 | |||
892 | if (!m0_name) | ||
893 | continue; | ||
894 | |||
895 | for (i = 0; i < OMAP_MUX_DEFNAME_LEN; i++) { | ||
896 | if (m0_name[i] == '\0') { | ||
897 | m0_def[i] = m0_name[i]; | ||
898 | break; | ||
899 | } | ||
900 | m0_def[i] = toupper(m0_name[i]); | ||
901 | } | ||
902 | val = omap_mux_read(m->reg_offset); | ||
903 | mode = val & OMAP_MUX_MODE7; | ||
904 | |||
905 | seq_printf(s, "OMAP%i_MUX(%s, ", | ||
906 | cpu_is_omap34xx() ? 3 : 0, m0_def); | ||
907 | omap_mux_decode(s, val); | ||
908 | seq_printf(s, "),\n"); | ||
909 | } | ||
910 | |||
911 | return 0; | ||
912 | } | ||
913 | |||
914 | static int omap_mux_dbg_board_open(struct inode *inode, struct file *file) | ||
915 | { | ||
916 | return single_open(file, omap_mux_dbg_board_show, &inode->i_private); | ||
917 | } | ||
918 | |||
919 | static const struct file_operations omap_mux_dbg_board_fops = { | ||
920 | .open = omap_mux_dbg_board_open, | ||
921 | .read = seq_read, | ||
922 | .llseek = seq_lseek, | ||
923 | .release = single_release, | ||
924 | }; | ||
925 | |||
926 | static int omap_mux_dbg_signal_show(struct seq_file *s, void *unused) | ||
927 | { | ||
928 | struct omap_mux *m = s->private; | ||
929 | const char *none = "NA"; | ||
930 | u16 val; | ||
931 | int mode; | ||
932 | |||
933 | val = omap_mux_read(m->reg_offset); | ||
934 | mode = val & OMAP_MUX_MODE7; | ||
935 | |||
936 | seq_printf(s, "name: %s.%s (0x%08lx/0x%03x = 0x%04x), b %s, t %s\n", | ||
937 | m->muxnames[0], m->muxnames[mode], | ||
938 | mux_phys + m->reg_offset, m->reg_offset, val, | ||
939 | m->balls[0] ? m->balls[0] : none, | ||
940 | m->balls[1] ? m->balls[1] : none); | ||
941 | seq_printf(s, "mode: "); | ||
942 | omap_mux_decode(s, val); | ||
943 | seq_printf(s, "\n"); | ||
944 | seq_printf(s, "signals: %s | %s | %s | %s | %s | %s | %s | %s\n", | ||
945 | m->muxnames[0] ? m->muxnames[0] : none, | ||
946 | m->muxnames[1] ? m->muxnames[1] : none, | ||
947 | m->muxnames[2] ? m->muxnames[2] : none, | ||
948 | m->muxnames[3] ? m->muxnames[3] : none, | ||
949 | m->muxnames[4] ? m->muxnames[4] : none, | ||
950 | m->muxnames[5] ? m->muxnames[5] : none, | ||
951 | m->muxnames[6] ? m->muxnames[6] : none, | ||
952 | m->muxnames[7] ? m->muxnames[7] : none); | ||
953 | |||
954 | return 0; | ||
955 | } | ||
956 | |||
957 | #define OMAP_MUX_MAX_ARG_CHAR 7 | ||
958 | |||
959 | static ssize_t omap_mux_dbg_signal_write(struct file *file, | ||
960 | const char __user *user_buf, | ||
961 | size_t count, loff_t *ppos) | ||
962 | { | ||
963 | char buf[OMAP_MUX_MAX_ARG_CHAR]; | ||
964 | struct seq_file *seqf; | ||
965 | struct omap_mux *m; | ||
966 | unsigned long val; | ||
967 | int buf_size, ret; | ||
968 | |||
969 | if (count > OMAP_MUX_MAX_ARG_CHAR) | ||
970 | return -EINVAL; | ||
971 | |||
972 | memset(buf, 0, sizeof(buf)); | ||
973 | buf_size = min(count, sizeof(buf) - 1); | ||
974 | |||
975 | if (copy_from_user(buf, user_buf, buf_size)) | ||
976 | return -EFAULT; | ||
977 | |||
978 | ret = strict_strtoul(buf, 0x10, &val); | ||
979 | if (ret < 0) | ||
980 | return ret; | ||
981 | |||
982 | if (val > 0xffff) | ||
983 | return -EINVAL; | ||
984 | |||
985 | seqf = file->private_data; | ||
986 | m = seqf->private; | ||
987 | |||
988 | omap_mux_write((u16)val, m->reg_offset); | ||
989 | *ppos += count; | ||
990 | |||
991 | return count; | ||
992 | } | ||
993 | |||
994 | static int omap_mux_dbg_signal_open(struct inode *inode, struct file *file) | ||
995 | { | ||
996 | return single_open(file, omap_mux_dbg_signal_show, inode->i_private); | ||
997 | } | ||
998 | |||
999 | static const struct file_operations omap_mux_dbg_signal_fops = { | ||
1000 | .open = omap_mux_dbg_signal_open, | ||
1001 | .read = seq_read, | ||
1002 | .write = omap_mux_dbg_signal_write, | ||
1003 | .llseek = seq_lseek, | ||
1004 | .release = single_release, | ||
1005 | }; | ||
1006 | |||
1007 | static struct dentry *mux_dbg_dir; | ||
1008 | |||
1009 | static void __init omap_mux_dbg_init(void) | ||
1010 | { | ||
1011 | struct omap_mux_entry *e; | ||
1012 | |||
1013 | mux_dbg_dir = debugfs_create_dir("omap_mux", NULL); | ||
1014 | if (!mux_dbg_dir) | ||
1015 | return; | ||
1016 | |||
1017 | (void)debugfs_create_file("board", S_IRUGO, mux_dbg_dir, | ||
1018 | NULL, &omap_mux_dbg_board_fops); | ||
1019 | |||
1020 | list_for_each_entry(e, &muxmodes, node) { | ||
1021 | struct omap_mux *m = &e->mux; | ||
1022 | |||
1023 | (void)debugfs_create_file(m->muxnames[0], S_IWUGO, mux_dbg_dir, | ||
1024 | m, &omap_mux_dbg_signal_fops); | ||
1025 | } | ||
1026 | } | ||
1027 | |||
1028 | #else | ||
1029 | static inline void omap_mux_dbg_init(void) | ||
1030 | { | ||
1031 | } | ||
1032 | #endif /* CONFIG_DEBUG_FS */ | ||
1033 | |||
810 | static void __init omap_mux_free_names(struct omap_mux *m) | 1034 | static void __init omap_mux_free_names(struct omap_mux *m) |
811 | { | 1035 | { |
812 | int i; | 1036 | int i; |
@@ -843,6 +1067,8 @@ static int __init omap_mux_late_init(void) | |||
843 | 1067 | ||
844 | } | 1068 | } |
845 | 1069 | ||
1070 | omap_mux_dbg_init(); | ||
1071 | |||
846 | return 0; | 1072 | return 0; |
847 | } | 1073 | } |
848 | late_initcall(omap_mux_late_init); | 1074 | late_initcall(omap_mux_late_init); |
@@ -1107,6 +1333,7 @@ int __init omap_mux_init(u32 mux_pbase, u32 mux_size, | |||
1107 | if (mux_base) | 1333 | if (mux_base) |
1108 | return -EBUSY; | 1334 | return -EBUSY; |
1109 | 1335 | ||
1336 | mux_phys = mux_pbase; | ||
1110 | mux_base = ioremap(mux_pbase, mux_size); | 1337 | mux_base = ioremap(mux_pbase, mux_size); |
1111 | if (!mux_base) { | 1338 | if (!mux_base) { |
1112 | printk(KERN_ERR "mux: Could not ioremap\n"); | 1339 | printk(KERN_ERR "mux: Could not ioremap\n"); |