diff options
Diffstat (limited to 'arch/arm/mach-omap2/mux.c')
-rw-r--r-- | arch/arm/mach-omap2/mux.c | 369 |
1 files changed, 249 insertions, 120 deletions
diff --git a/arch/arm/mach-omap2/mux.c b/arch/arm/mach-omap2/mux.c index 074536ae401..3d71d93caab 100644 --- a/arch/arm/mach-omap2/mux.c +++ b/arch/arm/mach-omap2/mux.c @@ -1,9 +1,9 @@ /* * linux/arch/arm/mach-omap2/mux.c * - * OMAP2 and OMAP3 pin multiplexing configurations + * OMAP2, OMAP3 and OMAP4 pin multiplexing configurations * - * Copyright (C) 2004 - 2008 Texas Instruments Inc. + * Copyright (C) 2004 - 2010 Texas Instruments Inc. * Copyright (C) 2003 - 2008 Nokia Corporation * * Written by Tony Lindgren @@ -40,60 +40,72 @@ #define OMAP_MUX_BASE_OFFSET 0x30 /* Offset from CTRL_BASE */ #define OMAP_MUX_BASE_SZ 0x5ca -#define MUXABLE_GPIO_MODE3 BIT(0) struct omap_mux_entry { struct omap_mux mux; struct list_head node; }; -static unsigned long mux_phys; -static void __iomem *mux_base; -static u8 omap_mux_flags; +static LIST_HEAD(mux_partitions); +static DEFINE_MUTEX(muxmode_mutex); -u16 omap_mux_read(u16 reg) +struct omap_mux_partition *omap_mux_get(const char *name) { - if (cpu_is_omap24xx()) - return __raw_readb(mux_base + reg); + struct omap_mux_partition *partition; + + list_for_each_entry(partition, &mux_partitions, node) { + if (!strcmp(name, partition->name)) + return partition; + } + + return NULL; +} + +u16 omap_mux_read(struct omap_mux_partition *partition, u16 reg) +{ + if (partition->flags & OMAP_MUX_REG_8BIT) + return __raw_readb(partition->base + reg); else - return __raw_readw(mux_base + reg); + return __raw_readw(partition->base + reg); } -void omap_mux_write(u16 val, u16 reg) +void omap_mux_write(struct omap_mux_partition *partition, u16 val, + u16 reg) { - if (cpu_is_omap24xx()) - __raw_writeb(val, mux_base + reg); + if (partition->flags & OMAP_MUX_REG_8BIT) + __raw_writeb(val, partition->base + reg); else - __raw_writew(val, mux_base + reg); + __raw_writew(val, partition->base + reg); } -void omap_mux_write_array(struct omap_board_mux *board_mux) +void omap_mux_write_array(struct omap_mux_partition *partition, + struct omap_board_mux *board_mux) { - while (board_mux->reg_offset != OMAP_MUX_TERMINATOR) { - omap_mux_write(board_mux->value, board_mux->reg_offset); + while (board_mux->reg_offset != OMAP_MUX_TERMINATOR) { + omap_mux_write(partition, board_mux->value, + board_mux->reg_offset); board_mux++; } } -static LIST_HEAD(muxmodes); -static DEFINE_MUTEX(muxmode_mutex); - #ifdef CONFIG_OMAP_MUX static char *omap_mux_options; -int __init omap_mux_init_gpio(int gpio, int val) +static int __init _omap_mux_init_gpio(struct omap_mux_partition *partition, + int gpio, int val) { struct omap_mux_entry *e; struct omap_mux *gpio_mux = NULL; u16 old_mode; u16 mux_mode; int found = 0; + struct list_head *muxmodes = &partition->muxmodes; if (!gpio) return -EINVAL; - list_for_each_entry(e, &muxmodes, node) { + list_for_each_entry(e, muxmodes, node) { struct omap_mux *m = &e->mux; if (gpio == m->gpio) { gpio_mux = m; @@ -102,34 +114,50 @@ int __init omap_mux_init_gpio(int gpio, int val) } if (found == 0) { - printk(KERN_ERR "mux: Could not set gpio%i\n", gpio); + pr_err("%s: Could not set gpio%i\n", __func__, gpio); return -ENODEV; } if (found > 1) { - printk(KERN_INFO "mux: Multiple gpio paths (%d) for gpio%i\n", - found, gpio); + pr_info("%s: Multiple gpio paths (%d) for gpio%i\n", __func__, + found, gpio); return -EINVAL; } - old_mode = omap_mux_read(gpio_mux->reg_offset); + old_mode = omap_mux_read(partition, gpio_mux->reg_offset); mux_mode = val & ~(OMAP_MUX_NR_MODES - 1); - if (omap_mux_flags & MUXABLE_GPIO_MODE3) + if (partition->flags & OMAP_MUX_GPIO_IN_MODE3) mux_mode |= OMAP_MUX_MODE3; else mux_mode |= OMAP_MUX_MODE4; - printk(KERN_DEBUG "mux: Setting signal %s.gpio%i 0x%04x -> 0x%04x\n", - gpio_mux->muxnames[0], gpio, old_mode, mux_mode); - omap_mux_write(mux_mode, gpio_mux->reg_offset); + pr_debug("%s: Setting signal %s.gpio%i 0x%04x -> 0x%04x\n", __func__, + gpio_mux->muxnames[0], gpio, old_mode, mux_mode); + omap_mux_write(partition, mux_mode, gpio_mux->reg_offset); return 0; } -int __init omap_mux_init_signal(const char *muxname, int val) +int __init omap_mux_init_gpio(int gpio, int val) +{ + struct omap_mux_partition *partition; + int ret; + + list_for_each_entry(partition, &mux_partitions, node) { + ret = _omap_mux_init_gpio(partition, gpio, val); + if (!ret) + return ret; + } + + return -ENODEV; +} + +static int __init _omap_mux_init_signal(struct omap_mux_partition *partition, + const char *muxname, int val) { struct omap_mux_entry *e; const char *mode_name; int found = 0, mode0_len = 0; + struct list_head *muxmodes = &partition->muxmodes; mode_name = strchr(muxname, '.'); if (mode_name) { @@ -139,7 +167,7 @@ int __init omap_mux_init_signal(const char *muxname, int val) mode_name = muxname; } - list_for_each_entry(e, &muxmodes, node) { + list_for_each_entry(e, muxmodes, node) { struct omap_mux *m = &e->mux; char *m0_entry = m->muxnames[0]; int i; @@ -159,12 +187,14 @@ int __init omap_mux_init_signal(const char *muxname, int val) u16 old_mode; u16 mux_mode; - old_mode = omap_mux_read(m->reg_offset); + old_mode = omap_mux_read(partition, + m->reg_offset); mux_mode = val | i; - printk(KERN_DEBUG "mux: Setting signal " - "%s.%s 0x%04x -> 0x%04x\n", - m0_entry, muxname, old_mode, mux_mode); - omap_mux_write(mux_mode, m->reg_offset); + pr_debug("%s: Setting signal " + "%s.%s 0x%04x -> 0x%04x\n", __func__, + m0_entry, muxname, old_mode, mux_mode); + omap_mux_write(partition, mux_mode, + m->reg_offset); found++; } } @@ -174,16 +204,31 @@ int __init omap_mux_init_signal(const char *muxname, int val) return 0; if (found > 1) { - printk(KERN_ERR "mux: Multiple signal paths (%i) for %s\n", - found, muxname); + pr_err("%s: Multiple signal paths (%i) for %s\n", __func__, + found, muxname); return -EINVAL; } - printk(KERN_ERR "mux: Could not set signal %s\n", muxname); + pr_err("%s: Could not set signal %s\n", __func__, muxname); return -ENODEV; } +int __init omap_mux_init_signal(const char *muxname, int val) +{ + struct omap_mux_partition *partition; + int ret; + + list_for_each_entry(partition, &mux_partitions, node) { + ret = _omap_mux_init_signal(partition, muxname, val); + if (!ret) + return ret; + } + + return -ENODEV; + +} + #ifdef CONFIG_DEBUG_FS #define OMAP_MUX_MAX_NR_FLAGS 10 @@ -248,13 +293,15 @@ static inline void omap_mux_decode(struct seq_file *s, u16 val) } while (i-- > 0); } -#define OMAP_MUX_DEFNAME_LEN 16 +#define OMAP_MUX_DEFNAME_LEN 32 static int omap_mux_dbg_board_show(struct seq_file *s, void *unused) { + struct omap_mux_partition *partition = s->private; struct omap_mux_entry *e; + u8 omap_gen = omap_rev() >> 28; - list_for_each_entry(e, &muxmodes, node) { + list_for_each_entry(e, &partition->muxmodes, node) { struct omap_mux *m = &e->mux; char m0_def[OMAP_MUX_DEFNAME_LEN]; char *m0_name = m->muxnames[0]; @@ -272,11 +319,16 @@ static int omap_mux_dbg_board_show(struct seq_file *s, void *unused) } m0_def[i] = toupper(m0_name[i]); } - val = omap_mux_read(m->reg_offset); + val = omap_mux_read(partition, m->reg_offset); mode = val & OMAP_MUX_MODE7; - - seq_printf(s, "OMAP%i_MUX(%s, ", - cpu_is_omap34xx() ? 3 : 0, m0_def); + if (mode != 0) + seq_printf(s, "/* %s */\n", m->muxnames[mode]); + + /* + * XXX: Might be revisited to support differences accross + * same OMAP generation. + */ + seq_printf(s, "OMAP%d_MUX(%s, ", omap_gen, m0_def); omap_mux_decode(s, val); seq_printf(s, "),\n"); } @@ -286,7 +338,7 @@ static int omap_mux_dbg_board_show(struct seq_file *s, void *unused) static int omap_mux_dbg_board_open(struct inode *inode, struct file *file) { - return single_open(file, omap_mux_dbg_board_show, &inode->i_private); + return single_open(file, omap_mux_dbg_board_show, inode->i_private); } static const struct file_operations omap_mux_dbg_board_fops = { @@ -296,19 +348,43 @@ static const struct file_operations omap_mux_dbg_board_fops = { .release = single_release, }; +static struct omap_mux_partition *omap_mux_get_partition(struct omap_mux *mux) +{ + struct omap_mux_partition *partition; + + list_for_each_entry(partition, &mux_partitions, node) { + struct list_head *muxmodes = &partition->muxmodes; + struct omap_mux_entry *e; + + list_for_each_entry(e, muxmodes, node) { + struct omap_mux *m = &e->mux; + + if (m == mux) + return partition; + } + } + + return NULL; +} + static int omap_mux_dbg_signal_show(struct seq_file *s, void *unused) { struct omap_mux *m = s->private; + struct omap_mux_partition *partition; const char *none = "NA"; u16 val; int mode; - val = omap_mux_read(m->reg_offset); + partition = omap_mux_get_partition(m); + if (!partition) + return 0; + + val = omap_mux_read(partition, m->reg_offset); mode = val & OMAP_MUX_MODE7; - seq_printf(s, "name: %s.%s (0x%08lx/0x%03x = 0x%04x), b %s, t %s\n", + seq_printf(s, "name: %s.%s (0x%08x/0x%03x = 0x%04x), b %s, t %s\n", m->muxnames[0], m->muxnames[mode], - mux_phys + m->reg_offset, m->reg_offset, val, + partition->phys + m->reg_offset, m->reg_offset, val, m->balls[0] ? m->balls[0] : none, m->balls[1] ? m->balls[1] : none); seq_printf(s, "mode: "); @@ -330,14 +406,15 @@ static int omap_mux_dbg_signal_show(struct seq_file *s, void *unused) #define OMAP_MUX_MAX_ARG_CHAR 7 static ssize_t omap_mux_dbg_signal_write(struct file *file, - const char __user *user_buf, - size_t count, loff_t *ppos) + const char __user *user_buf, + size_t count, loff_t *ppos) { char buf[OMAP_MUX_MAX_ARG_CHAR]; struct seq_file *seqf; struct omap_mux *m; unsigned long val; int buf_size, ret; + struct omap_mux_partition *partition; if (count > OMAP_MUX_MAX_ARG_CHAR) return -EINVAL; @@ -358,7 +435,11 @@ static ssize_t omap_mux_dbg_signal_write(struct file *file, seqf = file->private_data; m = seqf->private; - omap_mux_write((u16)val, m->reg_offset); + partition = omap_mux_get_partition(m); + if (!partition) + return -ENODEV; + + omap_mux_write(partition, (u16)val, m->reg_offset); *ppos += count; return count; @@ -379,22 +460,38 @@ static const struct file_operations omap_mux_dbg_signal_fops = { static struct dentry *mux_dbg_dir; -static void __init omap_mux_dbg_init(void) +static void __init omap_mux_dbg_create_entry( + struct omap_mux_partition *partition, + struct dentry *mux_dbg_dir) { struct omap_mux_entry *e; + list_for_each_entry(e, &partition->muxmodes, node) { + struct omap_mux *m = &e->mux; + + (void)debugfs_create_file(m->muxnames[0], S_IWUGO, mux_dbg_dir, + m, &omap_mux_dbg_signal_fops); + } +} + +static void __init omap_mux_dbg_init(void) +{ + struct omap_mux_partition *partition; + static struct dentry *mux_dbg_board_dir; + mux_dbg_dir = debugfs_create_dir("omap_mux", NULL); if (!mux_dbg_dir) return; - (void)debugfs_create_file("board", S_IRUGO, mux_dbg_dir, - NULL, &omap_mux_dbg_board_fops); - - list_for_each_entry(e, &muxmodes, node) { - struct omap_mux *m = &e->mux; + mux_dbg_board_dir = debugfs_create_dir("board", mux_dbg_dir); + if (!mux_dbg_board_dir) + return; - (void)debugfs_create_file(m->muxnames[0], S_IWUGO, mux_dbg_dir, - m, &omap_mux_dbg_signal_fops); + list_for_each_entry(partition, &mux_partitions, node) { + omap_mux_dbg_create_entry(partition, mux_dbg_dir); + (void)debugfs_create_file(partition->name, S_IRUGO, + mux_dbg_board_dir, partition, + &omap_mux_dbg_board_fops); } } @@ -421,23 +518,25 @@ static void __init omap_mux_free_names(struct omap_mux *m) /* Free all data except for GPIO pins unless CONFIG_DEBUG_FS is set */ static int __init omap_mux_late_init(void) { - struct omap_mux_entry *e, *tmp; + struct omap_mux_partition *partition; - list_for_each_entry_safe(e, tmp, &muxmodes, node) { - struct omap_mux *m = &e->mux; - u16 mode = omap_mux_read(m->reg_offset); + list_for_each_entry(partition, &mux_partitions, node) { + struct omap_mux_entry *e, *tmp; + list_for_each_entry_safe(e, tmp, &partition->muxmodes, node) { + struct omap_mux *m = &e->mux; + u16 mode = omap_mux_read(partition, m->reg_offset); - if (OMAP_MODE_GPIO(mode)) - continue; + if (OMAP_MODE_GPIO(mode)) + continue; #ifndef CONFIG_DEBUG_FS - mutex_lock(&muxmode_mutex); - list_del(&e->node); - mutex_unlock(&muxmode_mutex); - omap_mux_free_names(m); - kfree(m); + mutex_lock(&muxmode_mutex); + list_del(&e->node); + mutex_unlock(&muxmode_mutex); + omap_mux_free_names(m); + kfree(m); #endif - + } } omap_mux_dbg_init(); @@ -462,8 +561,8 @@ static void __init omap_mux_package_fixup(struct omap_mux *p, s++; } if (!found) - printk(KERN_ERR "mux: Unknown entry offset 0x%x\n", - p->reg_offset); + pr_err("%s: Unknown entry offset 0x%x\n", __func__, + p->reg_offset); p++; } } @@ -487,8 +586,8 @@ static void __init omap_mux_package_init_balls(struct omap_ball *b, s++; } if (!found) - printk(KERN_ERR "mux: Unknown ball offset 0x%x\n", - b->reg_offset); + pr_err("%s: Unknown ball offset 0x%x\n", __func__, + b->reg_offset); b++; } } @@ -554,7 +653,7 @@ static void __init omap_mux_set_cmdline_signals(void) } static int __init omap_mux_copy_names(struct omap_mux *src, - struct omap_mux *dst) + struct omap_mux *dst) { int i; @@ -592,51 +691,63 @@ free: #endif /* CONFIG_OMAP_MUX */ -static u16 omap_mux_get_by_gpio(int gpio) +static struct omap_mux *omap_mux_get_by_gpio( + struct omap_mux_partition *partition, + int gpio) { struct omap_mux_entry *e; - u16 offset = OMAP_MUX_TERMINATOR; + struct omap_mux *ret = NULL; - list_for_each_entry(e, &muxmodes, node) { + list_for_each_entry(e, &partition->muxmodes, node) { struct omap_mux *m = &e->mux; if (m->gpio == gpio) { - offset = m->reg_offset; + ret = m; break; } } - return offset; + return ret; } /* Needed for dynamic muxing of GPIO pins for off-idle */ u16 omap_mux_get_gpio(int gpio) { - u16 offset; + struct omap_mux_partition *partition; + struct omap_mux *m; - offset = omap_mux_get_by_gpio(gpio); - if (offset == OMAP_MUX_TERMINATOR) { - printk(KERN_ERR "mux: Could not get gpio%i\n", gpio); - return offset; + list_for_each_entry(partition, &mux_partitions, node) { + m = omap_mux_get_by_gpio(partition, gpio); + if (m) + return omap_mux_read(partition, m->reg_offset); } - return omap_mux_read(offset); + if (!m || m->reg_offset == OMAP_MUX_TERMINATOR) + pr_err("%s: Could not get gpio%i\n", __func__, gpio); + + return OMAP_MUX_TERMINATOR; } /* Needed for dynamic muxing of GPIO pins for off-idle */ void omap_mux_set_gpio(u16 val, int gpio) { - u16 offset; + struct omap_mux_partition *partition; + struct omap_mux *m = NULL; - offset = omap_mux_get_by_gpio(gpio); - if (offset == OMAP_MUX_TERMINATOR) { - printk(KERN_ERR "mux: Could not set gpio%i\n", gpio); - return; + list_for_each_entry(partition, &mux_partitions, node) { + m = omap_mux_get_by_gpio(partition, gpio); + if (m) { + omap_mux_write(partition, val, m->reg_offset); + return; + } } - omap_mux_write(val, offset); + if (!m || m->reg_offset == OMAP_MUX_TERMINATOR) + pr_err("%s: Could not set gpio%i\n", __func__, gpio); } -static struct omap_mux * __init omap_mux_list_add(struct omap_mux *src) +static struct omap_mux * __init omap_mux_list_add( + struct omap_mux_partition *partition, + struct omap_mux *src) { struct omap_mux_entry *entry; struct omap_mux *m; @@ -656,7 +767,7 @@ static struct omap_mux * __init omap_mux_list_add(struct omap_mux *src) #endif mutex_lock(&muxmode_mutex); - list_add_tail(&entry->node, &muxmodes); + list_add_tail(&entry->node, &partition->muxmodes); mutex_unlock(&muxmode_mutex); return m; @@ -667,7 +778,8 @@ static struct omap_mux * __init omap_mux_list_add(struct omap_mux *src) * the GPIO to mux offset mapping that is needed for dynamic muxing * of GPIO pins for off-idle. */ -static void __init omap_mux_init_list(struct omap_mux *superset) +static void __init omap_mux_init_list(struct omap_mux_partition *partition, + struct omap_mux *superset) { while (superset->reg_offset != OMAP_MUX_TERMINATOR) { struct omap_mux *entry; @@ -679,15 +791,16 @@ static void __init omap_mux_init_list(struct omap_mux *superset) } #else /* Skip pins that are not muxed as GPIO by bootloader */ - if (!OMAP_MODE_GPIO(omap_mux_read(superset->reg_offset))) { + if (!OMAP_MODE_GPIO(omap_mux_read(partition, + superset->reg_offset))) { superset++; continue; } #endif - entry = omap_mux_list_add(superset); + entry = omap_mux_list_add(partition, superset); if (!entry) { - printk(KERN_ERR "mux: Could not add entry\n"); + pr_err("%s: Could not add entry\n", __func__); return; } superset++; @@ -706,10 +819,11 @@ static void omap_mux_init_package(struct omap_mux *superset, omap_mux_package_init_balls(package_balls, superset); } -static void omap_mux_init_signals(struct omap_board_mux *board_mux) +static void omap_mux_init_signals(struct omap_mux_partition *partition, + struct omap_board_mux *board_mux) { omap_mux_set_cmdline_signals(); - omap_mux_write_array(board_mux); + omap_mux_write_array(partition, board_mux); } #else @@ -720,34 +834,49 @@ static void omap_mux_init_package(struct omap_mux *superset, { } -static void omap_mux_init_signals(struct omap_board_mux *board_mux) +static void omap_mux_init_signals(struct omap_mux_partition *partition, + struct omap_board_mux *board_mux) { } #endif -int __init omap_mux_init(u32 mux_pbase, u32 mux_size, - struct omap_mux *superset, - struct omap_mux *package_subset, - struct omap_board_mux *board_mux, - struct omap_ball *package_balls) -{ - if (mux_base) - return -EBUSY; +static u32 mux_partitions_cnt; - mux_phys = mux_pbase; - mux_base = ioremap(mux_pbase, mux_size); - if (!mux_base) { - printk(KERN_ERR "mux: Could not ioremap\n"); +int __init omap_mux_init(const char *name, u32 flags, + u32 mux_pbase, u32 mux_size, + struct omap_mux *superset, + struct omap_mux *package_subset, + struct omap_board_mux *board_mux, + struct omap_ball *package_balls) +{ + struct omap_mux_partition *partition; + + partition = kzalloc(sizeof(struct omap_mux_partition), GFP_KERNEL); + if (!partition) + return -ENOMEM; + + partition->name = name; + partition->flags = flags; + partition->size = mux_size; + partition->phys = mux_pbase; + partition->base = ioremap(mux_pbase, mux_size); + if (!partition->base) { + pr_err("%s: Could not ioremap mux partition at 0x%08x\n", + __func__, partition->phys); return -ENODEV; } - if (cpu_is_omap24xx()) - omap_mux_flags = MUXABLE_GPIO_MODE3; + INIT_LIST_HEAD(&partition->muxmodes); + + list_add_tail(&partition->node, &mux_partitions); + mux_partitions_cnt++; + pr_info("%s: Add partition: #%d: %s, flags: %x\n", __func__, + mux_partitions_cnt, partition->name, partition->flags); omap_mux_init_package(superset, package_subset, package_balls); - omap_mux_init_list(superset); - omap_mux_init_signals(board_mux); + omap_mux_init_list(partition, superset); + omap_mux_init_signals(partition, board_mux); return 0; } |