Merge branch 'upstream-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jgarzi...
[pandora-kernel.git] / arch / arm / mach-omap2 / mux.c
index 3d71d93..17bd639 100644 (file)
@@ -35,6 +35,8 @@
 
 #include <asm/system.h>
 
+#include <plat/omap_hwmod.h>
+
 #include "control.h"
 #include "mux.h"
 
@@ -151,12 +153,14 @@ int __init omap_mux_init_gpio(int gpio, int val)
        return -ENODEV;
 }
 
-static int __init _omap_mux_init_signal(struct omap_mux_partition *partition,
-                                       const char *muxname, int val)
+static int __init _omap_mux_get_by_name(struct omap_mux_partition *partition,
+                                       const char *muxname,
+                                       struct omap_mux **found_mux)
 {
+       struct omap_mux *mux = NULL;
        struct omap_mux_entry *e;
        const char *mode_name;
-       int found = 0, mode0_len = 0;
+       int found = 0, found_mode, mode0_len = 0;
        struct list_head *muxmodes = &partition->muxmodes;
 
        mode_name = strchr(muxname, '.');
@@ -168,40 +172,34 @@ static int __init _omap_mux_init_signal(struct omap_mux_partition *partition,
        }
 
        list_for_each_entry(e, muxmodes, node) {
-               struct omap_mux *m = &e->mux;
-               char *m0_entry = m->muxnames[0];
+               char *m0_entry;
                int i;
 
+               mux = &e->mux;
+               m0_entry = mux->muxnames[0];
+
                /* First check for full name in mode0.muxmode format */
                if (mode0_len && strncmp(muxname, m0_entry, mode0_len))
                        continue;
 
                /* Then check for muxmode only */
                for (i = 0; i < OMAP_MUX_NR_MODES; i++) {
-                       char *mode_cur = m->muxnames[i];
+                       char *mode_cur = mux->muxnames[i];
 
                        if (!mode_cur)
                                continue;
 
                        if (!strcmp(mode_name, mode_cur)) {
-                               u16 old_mode;
-                               u16 mux_mode;
-
-                               old_mode = omap_mux_read(partition,
-                                                        m->reg_offset);
-                               mux_mode = val | i;
-                               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_mux = mux;
                                found++;
+                               found_mode = i;
                        }
                }
        }
 
-       if (found == 1)
-               return 0;
+       if (found == 1) {
+               return found_mode;
+       }
 
        if (found > 1) {
                pr_err("%s: Multiple signal paths (%i) for %s\n", __func__,
@@ -209,24 +207,162 @@ static int __init _omap_mux_init_signal(struct omap_mux_partition *partition,
                return -EINVAL;
        }
 
-       pr_err("%s: Could not set signal %s\n", __func__, muxname);
+       pr_err("%s: Could not find signal %s\n", __func__, muxname);
 
        return -ENODEV;
 }
 
-int __init omap_mux_init_signal(const char *muxname, int val)
+static int __init
+omap_mux_get_by_name(const char *muxname,
+                       struct omap_mux_partition **found_partition,
+                       struct omap_mux **found_mux)
 {
        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;
+               struct omap_mux *mux = NULL;
+               int mux_mode = _omap_mux_get_by_name(partition, muxname, &mux);
+               if (mux_mode < 0)
+                       continue;
+
+               *found_partition = partition;
+               *found_mux = mux;
+
+               return mux_mode;
        }
 
        return -ENODEV;
+}
+
+int __init omap_mux_init_signal(const char *muxname, int val)
+{
+       struct omap_mux_partition *partition = NULL;
+       struct omap_mux *mux = NULL;
+       u16 old_mode;
+       int mux_mode;
+
+       mux_mode = omap_mux_get_by_name(muxname, &partition, &mux);
+       if (mux_mode < 0)
+               return mux_mode;
 
+       old_mode = omap_mux_read(partition, mux->reg_offset);
+       mux_mode |= val;
+       pr_debug("%s: Setting signal %s 0x%04x -> 0x%04x\n",
+                        __func__, muxname, old_mode, mux_mode);
+       omap_mux_write(partition, mux_mode, mux->reg_offset);
+
+       return 0;
+}
+
+struct omap_hwmod_mux_info * __init
+omap_hwmod_mux_init(struct omap_device_pad *bpads, int nr_pads)
+{
+       struct omap_hwmod_mux_info *hmux;
+       int i;
+
+       if (!bpads || nr_pads < 1)
+               return NULL;
+
+       hmux = kzalloc(sizeof(struct omap_hwmod_mux_info), GFP_KERNEL);
+       if (!hmux)
+               goto err1;
+
+       hmux->nr_pads = nr_pads;
+
+       hmux->pads = kzalloc(sizeof(struct omap_device_pad) *
+                               nr_pads, GFP_KERNEL);
+       if (!hmux->pads)
+               goto err2;
+
+       for (i = 0; i < hmux->nr_pads; i++) {
+               struct omap_mux_partition *partition;
+               struct omap_device_pad *bpad = &bpads[i], *pad = &hmux->pads[i];
+               struct omap_mux *mux;
+               int mux_mode;
+
+               mux_mode = omap_mux_get_by_name(bpad->name, &partition, &mux);
+               if (mux_mode < 0)
+                       goto err3;
+               if (!pad->partition)
+                       pad->partition = partition;
+               if (!pad->mux)
+                       pad->mux = mux;
+
+               pad->name = kzalloc(strlen(bpad->name) + 1, GFP_KERNEL);
+               if (!pad->name) {
+                       int j;
+
+                       for (j = i - 1; j >= 0; j--)
+                               kfree(hmux->pads[j].name);
+                       goto err3;
+               }
+               strcpy(pad->name, bpad->name);
+
+               pad->flags = bpad->flags;
+               pad->enable = bpad->enable;
+               pad->idle = bpad->idle;
+               pad->off = bpad->off;
+               pr_debug("%s: Initialized %s\n", __func__, pad->name);
+       }
+
+       return hmux;
+
+err3:
+       kfree(hmux->pads);
+err2:
+       kfree(hmux);
+err1:
+       pr_err("%s: Could not allocate device mux entry\n", __func__);
+
+       return NULL;
+}
+
+/* Assumes the calling function takes care of locking */
+void omap_hwmod_mux(struct omap_hwmod_mux_info *hmux, u8 state)
+{
+       int i;
+
+       for (i = 0; i < hmux->nr_pads; i++) {
+               struct omap_device_pad *pad = &hmux->pads[i];
+               int flags, val = -EINVAL;
+
+               flags = pad->flags;
+
+               switch (state) {
+               case _HWMOD_STATE_ENABLED:
+                       if (flags & OMAP_DEVICE_PAD_ENABLED)
+                               break;
+                       flags |= OMAP_DEVICE_PAD_ENABLED;
+                       val = pad->enable;
+                       pr_debug("%s: Enabling %s %x\n", __func__,
+                                       pad->name, val);
+                       break;
+               case _HWMOD_STATE_IDLE:
+                       if (!(flags & OMAP_DEVICE_PAD_REMUX))
+                               break;
+                       flags &= ~OMAP_DEVICE_PAD_ENABLED;
+                       val = pad->idle;
+                       pr_debug("%s: Idling %s %x\n", __func__,
+                                       pad->name, val);
+                       break;
+               case _HWMOD_STATE_DISABLED:
+               default:
+                       /* Use safe mode unless OMAP_DEVICE_PAD_REMUX */
+                       if (flags & OMAP_DEVICE_PAD_REMUX)
+                               val = pad->off;
+                       else
+                               val = OMAP_MUX_MODE7;
+                       flags &= ~OMAP_DEVICE_PAD_ENABLED;
+                       pr_debug("%s: Disabling %s %x\n", __func__,
+                                       pad->name, val);
+               };
+
+               if (val >= 0) {
+                       omap_mux_write(pad->partition, val,
+                                       pad->mux->reg_offset);
+                       pad->flags = flags;
+               }
+       }
 }
 
 #ifdef CONFIG_DEBUG_FS