aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-omap2/mux.c
diff options
context:
space:
mode:
authorTony Lindgren <tony@atomide.com>2009-12-11 19:16:32 -0500
committerTony Lindgren <tony@atomide.com>2009-12-11 19:16:32 -0500
commit15ac7afe515631ec36966b1cf632a87276536f57 (patch)
tree68fae5c0154ccf441468569c0d763b32c3b90f21 /arch/arm/mach-omap2/mux.c
parent92c9f5018997dbc5f5e91eae2400d78ada2760b0 (diff)
omap: mux: Add new style pin multiplexing code for omap3
Initially only for 34xx. This code allows us to: - Make the code more generic as the omap internal signal names can stay the same across omap generations for some devices - Map mux registers to GPIO registers that is needed for dynamic muxing of pins during off-idle - Override bootloader mux values via kernel cmdline using omap_mux=some.signa1=0x1234,some.signal2=0x1234 - View and set the mux registers via debugfs if CONFIG_DEBUG_FS is enabled Cc: Mike Rapoport <mike@compulab.co.il> Cc: Benoit Cousson <b-cousson@ti.com> Signed-off-by: Paul Walmsley <paul@pwsan.com> Signed-off-by: Tony Lindgren <tony@atomide.com>
Diffstat (limited to 'arch/arm/mach-omap2/mux.c')
-rw-r--r--arch/arm/mach-omap2/mux.c444
1 files changed, 440 insertions, 4 deletions
diff --git a/arch/arm/mach-omap2/mux.c b/arch/arm/mach-omap2/mux.c
index 64250c504c64..b082b504de8b 100644
--- a/arch/arm/mach-omap2/mux.c
+++ b/arch/arm/mach-omap2/mux.c
@@ -27,18 +27,23 @@
27#include <linux/init.h> 27#include <linux/init.h>
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 31
31#include <asm/system.h> 32#include <asm/system.h>
32 33
33#include <plat/control.h> 34#include <plat/control.h>
34#include <plat/mux.h> 35#include <plat/mux.h>
35 36
36#ifdef CONFIG_OMAP_MUX 37#include "mux.h"
37 38
38#define OMAP_MUX_BASE_OFFSET 0x30 /* Offset from CTRL_BASE */ 39#define OMAP_MUX_BASE_OFFSET 0x30 /* Offset from CTRL_BASE */
39#define OMAP_MUX_BASE_SZ 0x5ca 40#define OMAP_MUX_BASE_SZ 0x5ca
40 41
41static struct omap_mux_cfg arch_mux_cfg; 42struct omap_mux_entry {
43 struct omap_mux mux;
44 struct list_head node;
45};
46
42static void __iomem *mux_base; 47static void __iomem *mux_base;
43 48
44static inline u16 omap_mux_read(u16 reg) 49static inline u16 omap_mux_read(u16 reg)
@@ -57,6 +62,10 @@ static inline void omap_mux_write(u16 val, u16 reg)
57 __raw_writew(val, mux_base + reg); 62 __raw_writew(val, mux_base + reg);
58} 63}
59 64
65#ifdef CONFIG_OMAP_MUX
66
67static struct omap_mux_cfg arch_mux_cfg;
68
60/* NOTE: See mux.h for the enumeration */ 69/* NOTE: See mux.h for the enumeration */
61 70
62#ifdef CONFIG_ARCH_OMAP24XX 71#ifdef CONFIG_ARCH_OMAP24XX
@@ -667,8 +676,8 @@ int __init omap2_mux_init(void)
667 mux_pbase = OMAP2420_CTRL_BASE + OMAP_MUX_BASE_OFFSET; 676 mux_pbase = OMAP2420_CTRL_BASE + OMAP_MUX_BASE_OFFSET;
668 else if (cpu_is_omap2430()) 677 else if (cpu_is_omap2430())
669 mux_pbase = OMAP243X_CTRL_BASE + OMAP_MUX_BASE_OFFSET; 678 mux_pbase = OMAP243X_CTRL_BASE + OMAP_MUX_BASE_OFFSET;
670 else if (cpu_is_omap34xx()) 679 else
671 mux_pbase = OMAP343X_CTRL_BASE + OMAP_MUX_BASE_OFFSET; 680 return -ENODEV;
672 681
673 mux_base = ioremap(mux_pbase, OMAP_MUX_BASE_SZ); 682 mux_base = ioremap(mux_pbase, OMAP_MUX_BASE_SZ);
674 if (!mux_base) { 683 if (!mux_base) {
@@ -689,4 +698,431 @@ int __init omap2_mux_init(void)
689 return omap_mux_register(&arch_mux_cfg); 698 return omap_mux_register(&arch_mux_cfg);
690} 699}
691 700
701#endif /* CONFIG_OMAP_MUX */
702
703/*----------------------------------------------------------------------------*/
704
705#ifdef CONFIG_ARCH_OMAP34XX
706
707static LIST_HEAD(muxmodes);
708static DEFINE_MUTEX(muxmode_mutex);
709
710#ifdef CONFIG_OMAP_MUX
711
712static char *omap_mux_options;
713
714int __init omap_mux_init_gpio(int gpio, int val)
715{
716 struct omap_mux_entry *e;
717 int found = 0;
718
719 if (!gpio)
720 return -EINVAL;
721
722 list_for_each_entry(e, &muxmodes, node) {
723 struct omap_mux *m = &e->mux;
724 if (gpio == m->gpio) {
725 u16 old_mode;
726 u16 mux_mode;
727
728 old_mode = omap_mux_read(m->reg_offset);
729 mux_mode = val & ~(OMAP_MUX_NR_MODES - 1);
730 mux_mode |= OMAP_MUX_MODE4;
731 printk(KERN_DEBUG "mux: Setting signal "
732 "%s.gpio%i 0x%04x -> 0x%04x\n",
733 m->muxnames[0], gpio, old_mode, mux_mode);
734 omap_mux_write(mux_mode, m->reg_offset);
735 found++;
736 }
737 }
738
739 if (found == 1)
740 return 0;
741
742 if (found > 1) {
743 printk(KERN_ERR "mux: Multiple gpio paths for gpio%i\n", gpio);
744 return -EINVAL;
745 }
746
747 printk(KERN_ERR "mux: Could not set gpio%i\n", gpio);
748
749 return -ENODEV;
750}
751
752int __init omap_mux_init_signal(char *muxname, int val)
753{
754 struct omap_mux_entry *e;
755 char *m0_name = NULL, *mode_name = NULL;
756 int found = 0;
757
758 mode_name = strchr(muxname, '.');
759 if (mode_name) {
760 *mode_name = '\0';
761 mode_name++;
762 m0_name = muxname;
763 } else {
764 mode_name = muxname;
765 }
766
767 list_for_each_entry(e, &muxmodes, node) {
768 struct omap_mux *m = &e->mux;
769 char *m0_entry = m->muxnames[0];
770 int i;
771
772 if (m0_name && strcmp(m0_name, m0_entry))
773 continue;
774
775 for (i = 0; i < OMAP_MUX_NR_MODES; i++) {
776 char *mode_cur = m->muxnames[i];
777
778 if (!mode_cur)
779 continue;
780
781 if (!strcmp(mode_name, mode_cur)) {
782 u16 old_mode;
783 u16 mux_mode;
784
785 old_mode = omap_mux_read(m->reg_offset);
786 mux_mode = val | i;
787 printk(KERN_DEBUG "mux: Setting signal "
788 "%s.%s 0x%04x -> 0x%04x\n",
789 m0_entry, muxname, old_mode, mux_mode);
790 omap_mux_write(mux_mode, m->reg_offset);
791 found++;
792 }
793 }
794 }
795
796 if (found == 1)
797 return 0;
798
799 if (found > 1) {
800 printk(KERN_ERR "mux: Multiple signal paths (%i) for %s\n",
801 found, muxname);
802 return -EINVAL;
803 }
804
805 printk(KERN_ERR "mux: Could not set signal %s\n", muxname);
806
807 return -ENODEV;
808}
809
810static void __init omap_mux_free_names(struct omap_mux *m)
811{
812 int i;
813
814 for (i = 0; i < OMAP_MUX_NR_MODES; i++)
815 kfree(m->muxnames[i]);
816
817#ifdef CONFIG_DEBUG_FS
818 for (i = 0; i < OMAP_MUX_NR_SIDES; i++)
819 kfree(m->balls[i]);
820#endif
821
822}
823
824/* Free all data except for GPIO pins unless CONFIG_DEBUG_FS is set */
825static int __init omap_mux_late_init(void)
826{
827 struct omap_mux_entry *e, *tmp;
828
829 list_for_each_entry_safe(e, tmp, &muxmodes, node) {
830 struct omap_mux *m = &e->mux;
831 u16 mode = omap_mux_read(m->reg_offset);
832
833 if (OMAP_MODE_GPIO(mode))
834 continue;
835
836#ifndef CONFIG_DEBUG_FS
837 mutex_lock(&muxmode_mutex);
838 list_del(&e->node);
839 mutex_unlock(&muxmode_mutex);
840 omap_mux_free_names(m);
841 kfree(m);
692#endif 842#endif
843
844 }
845
846 return 0;
847}
848late_initcall(omap_mux_late_init);
849
850static void __init omap_mux_package_fixup(struct omap_mux *p,
851 struct omap_mux *superset)
852{
853 while (p->reg_offset != OMAP_MUX_TERMINATOR) {
854 struct omap_mux *s = superset;
855 int found = 0;
856
857 while (s->reg_offset != OMAP_MUX_TERMINATOR) {
858 if (s->reg_offset == p->reg_offset) {
859 *s = *p;
860 found++;
861 break;
862 }
863 s++;
864 }
865 if (!found)
866 printk(KERN_ERR "mux: Unknown entry offset 0x%x\n",
867 p->reg_offset);
868 p++;
869 }
870}
871
872#ifdef CONFIG_DEBUG_FS
873
874static void __init omap_mux_package_init_balls(struct omap_ball *b,
875 struct omap_mux *superset)
876{
877 while (b->reg_offset != OMAP_MUX_TERMINATOR) {
878 struct omap_mux *s = superset;
879 int found = 0;
880
881 while (s->reg_offset != OMAP_MUX_TERMINATOR) {
882 if (s->reg_offset == b->reg_offset) {
883 s->balls[0] = b->balls[0];
884 s->balls[1] = b->balls[1];
885 found++;
886 break;
887 }
888 s++;
889 }
890 if (!found)
891 printk(KERN_ERR "mux: Unknown ball offset 0x%x\n",
892 b->reg_offset);
893 b++;
894 }
895}
896
897#else /* CONFIG_DEBUG_FS */
898
899static inline void omap_mux_package_init_balls(struct omap_ball *b,
900 struct omap_mux *superset)
901{
902}
903
904#endif /* CONFIG_DEBUG_FS */
905
906static int __init omap_mux_setup(char *options)
907{
908 if (!options)
909 return 0;
910
911 omap_mux_options = options;
912
913 return 1;
914}
915__setup("omap_mux=", omap_mux_setup);
916
917/*
918 * Note that the omap_mux=some.signal1=0x1234,some.signal2=0x1234
919 * cmdline options only override the bootloader values.
920 * During development, please enable CONFIG_DEBUG_FS, and use the
921 * signal specific entries under debugfs.
922 */
923static void __init omap_mux_set_cmdline_signals(void)
924{
925 char *options, *next_opt, *token;
926
927 if (!omap_mux_options)
928 return;
929
930 options = kmalloc(strlen(omap_mux_options) + 1, GFP_KERNEL);
931 if (!options)
932 return;
933
934 strcpy(options, omap_mux_options);
935 next_opt = options;
936
937 while ((token = strsep(&next_opt, ",")) != NULL) {
938 char *keyval, *name;
939 unsigned long val;
940
941 keyval = token;
942 name = strsep(&keyval, "=");
943 if (name) {
944 int res;
945
946 res = strict_strtoul(keyval, 0x10, &val);
947 if (res < 0)
948 continue;
949
950 omap_mux_init_signal(name, (u16)val);
951 }
952 }
953
954 kfree(options);
955}
956
957static void __init omap_mux_set_board_signals(struct omap_board_mux *board_mux)
958{
959 while (board_mux->reg_offset != OMAP_MUX_TERMINATOR) {
960 omap_mux_write(board_mux->value, board_mux->reg_offset);
961 board_mux++;
962 }
963}
964
965static int __init omap_mux_copy_names(struct omap_mux *src,
966 struct omap_mux *dst)
967{
968 int i;
969
970 for (i = 0; i < OMAP_MUX_NR_MODES; i++) {
971 if (src->muxnames[i]) {
972 dst->muxnames[i] =
973 kmalloc(strlen(src->muxnames[i]) + 1,
974 GFP_KERNEL);
975 if (!dst->muxnames[i])
976 goto free;
977 strcpy(dst->muxnames[i], src->muxnames[i]);
978 }
979 }
980
981#ifdef CONFIG_DEBUG_FS
982 for (i = 0; i < OMAP_MUX_NR_SIDES; i++) {
983 if (src->balls[i]) {
984 dst->balls[i] =
985 kmalloc(strlen(src->balls[i]) + 1,
986 GFP_KERNEL);
987 if (!dst->balls[i])
988 goto free;
989 strcpy(dst->balls[i], src->balls[i]);
990 }
991 }
992#endif
993
994 return 0;
995
996free:
997 omap_mux_free_names(dst);
998 return -ENOMEM;
999
1000}
1001
1002#endif /* CONFIG_OMAP_MUX */
1003
1004static u16 omap_mux_get_by_gpio(int gpio)
1005{
1006 struct omap_mux_entry *e;
1007 u16 offset = OMAP_MUX_TERMINATOR;
1008
1009 list_for_each_entry(e, &muxmodes, node) {
1010 struct omap_mux *m = &e->mux;
1011 if (m->gpio == gpio) {
1012 offset = m->reg_offset;
1013 break;
1014 }
1015 }
1016
1017 return offset;
1018}
1019
1020/* Needed for dynamic muxing of GPIO pins for off-idle */
1021u16 omap_mux_get_gpio(int gpio)
1022{
1023 u16 offset;
1024
1025 offset = omap_mux_get_by_gpio(gpio);
1026 if (offset == OMAP_MUX_TERMINATOR) {
1027 printk(KERN_ERR "mux: Could not get gpio%i\n", gpio);
1028 return offset;
1029 }
1030
1031 return omap_mux_read(offset);
1032}
1033
1034/* Needed for dynamic muxing of GPIO pins for off-idle */
1035void omap_mux_set_gpio(u16 val, int gpio)
1036{
1037 u16 offset;
1038
1039 offset = omap_mux_get_by_gpio(gpio);
1040 if (offset == OMAP_MUX_TERMINATOR) {
1041 printk(KERN_ERR "mux: Could not set gpio%i\n", gpio);
1042 return;
1043 }
1044
1045 omap_mux_write(val, offset);
1046}
1047
1048static struct omap_mux * __init omap_mux_list_add(struct omap_mux *src)
1049{
1050 struct omap_mux_entry *entry;
1051 struct omap_mux *m;
1052
1053 entry = kzalloc(sizeof(struct omap_mux_entry), GFP_KERNEL);
1054 if (!entry)
1055 return NULL;
1056
1057 m = &entry->mux;
1058 memcpy(m, src, sizeof(struct omap_mux_entry));
1059
1060#ifdef CONFIG_OMAP_MUX
1061 if (omap_mux_copy_names(src, m)) {
1062 kfree(entry);
1063 return NULL;
1064 }
1065#endif
1066
1067 mutex_lock(&muxmode_mutex);
1068 list_add_tail(&entry->node, &muxmodes);
1069 mutex_unlock(&muxmode_mutex);
1070
1071 return m;
1072}
1073
1074/*
1075 * Note if CONFIG_OMAP_MUX is not selected, we will only initialize
1076 * the GPIO to mux offset mapping that is needed for dynamic muxing
1077 * of GPIO pins for off-idle.
1078 */
1079static void __init omap_mux_init_list(struct omap_mux *superset)
1080{
1081 while (superset->reg_offset != OMAP_MUX_TERMINATOR) {
1082 struct omap_mux *entry;
1083
1084#ifndef CONFIG_OMAP_MUX
1085 /* Skip pins that are not muxed as GPIO by bootloader */
1086 if (!OMAP_MODE_GPIO(omap_mux_read(superset->reg_offset))) {
1087 superset++;
1088 continue;
1089 }
1090#endif
1091
1092 entry = omap_mux_list_add(superset);
1093 if (!entry) {
1094 printk(KERN_ERR "mux: Could not add entry\n");
1095 return;
1096 }
1097 superset++;
1098 }
1099}
1100
1101int __init omap_mux_init(u32 mux_pbase, u32 mux_size,
1102 struct omap_mux *superset,
1103 struct omap_mux *package_subset,
1104 struct omap_board_mux *board_mux,
1105 struct omap_ball *package_balls)
1106{
1107 if (mux_base)
1108 return -EBUSY;
1109
1110 mux_base = ioremap(mux_pbase, mux_size);
1111 if (!mux_base) {
1112 printk(KERN_ERR "mux: Could not ioremap\n");
1113 return -ENODEV;
1114 }
1115
1116#ifdef CONFIG_OMAP_MUX
1117 omap_mux_package_fixup(package_subset, superset);
1118 omap_mux_package_init_balls(package_balls, superset);
1119 omap_mux_set_cmdline_signals();
1120 omap_mux_set_board_signals(board_mux);
1121#endif
1122
1123 omap_mux_init_list(superset);
1124
1125 return 0;
1126}
1127
1128#endif /* CONFIG_ARCH_OMAP34XX */