Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid
[pandora-kernel.git] / arch / arm / mach-msm / vreg.c
index fcb0b9f..a9103bc 100644 (file)
@@ -1,6 +1,7 @@
 /* arch/arm/mach-msm/vreg.c
  *
  * Copyright (C) 2008 Google, Inc.
+ * Copyright (c) 2009, Code Aurora Forum. All rights reserved.
  * Author: Brian Swetland <swetland@google.com>
  *
  * This software is licensed under the terms of the GNU General Public
@@ -18,6 +19,7 @@
 #include <linux/device.h>
 #include <linux/init.h>
 #include <linux/debugfs.h>
+#include <linux/string.h>
 #include <mach/vreg.h>
 
 #include "proc_comm.h"
 struct vreg {
        const char *name;
        unsigned id;
+       int status;
+       unsigned refcnt;
 };
 
-#define VREG(_name, _id) { .name = _name, .id = _id, }
+#define VREG(_name, _id, _status, _refcnt) \
+       { .name = _name, .id = _id, .status = _status, .refcnt = _refcnt }
 
 static struct vreg vregs[] = {
-       VREG("msma",    0),
-       VREG("msmp",    1),
-       VREG("msme1",   2),
-       VREG("msmc1",   3),
-       VREG("msmc2",   4),
-       VREG("gp3",     5),
-       VREG("msme2",   6),
-       VREG("gp4",     7),
-       VREG("gp1",     8),
-       VREG("tcxo",    9),
-       VREG("pa",      10),
-       VREG("rftx",    11),
-       VREG("rfrx1",   12),
-       VREG("rfrx2",   13),
-       VREG("synt",    14),
-       VREG("wlan",    15),
-       VREG("usb",     16),
-       VREG("boost",   17),
-       VREG("mmc",     18),
-       VREG("ruim",    19),
-       VREG("msmc0",   20),
-       VREG("gp2",     21),
-       VREG("gp5",     22),
-       VREG("gp6",     23),
-       VREG("rf",      24),
-       VREG("rf_vco",  26),
-       VREG("mpll",    27),
-       VREG("s2",      28),
-       VREG("s3",      29),
-       VREG("rfubm",   30),
-       VREG("ncp",     31),
+       VREG("msma",    0, 0, 0),
+       VREG("msmp",    1, 0, 0),
+       VREG("msme1",   2, 0, 0),
+       VREG("msmc1",   3, 0, 0),
+       VREG("msmc2",   4, 0, 0),
+       VREG("gp3",     5, 0, 0),
+       VREG("msme2",   6, 0, 0),
+       VREG("gp4",     7, 0, 0),
+       VREG("gp1",     8, 0, 0),
+       VREG("tcxo",    9, 0, 0),
+       VREG("pa",      10, 0, 0),
+       VREG("rftx",    11, 0, 0),
+       VREG("rfrx1",   12, 0, 0),
+       VREG("rfrx2",   13, 0, 0),
+       VREG("synt",    14, 0, 0),
+       VREG("wlan",    15, 0, 0),
+       VREG("usb",     16, 0, 0),
+       VREG("boost",   17, 0, 0),
+       VREG("mmc",     18, 0, 0),
+       VREG("ruim",    19, 0, 0),
+       VREG("msmc0",   20, 0, 0),
+       VREG("gp2",     21, 0, 0),
+       VREG("gp5",     22, 0, 0),
+       VREG("gp6",     23, 0, 0),
+       VREG("rf",      24, 0, 0),
+       VREG("rf_vco",  26, 0, 0),
+       VREG("mpll",    27, 0, 0),
+       VREG("s2",      28, 0, 0),
+       VREG("s3",      29, 0, 0),
+       VREG("rfubm",   30, 0, 0),
+       VREG("ncp",     31, 0, 0),
+       VREG("gp7",     32, 0, 0),
+       VREG("gp8",     33, 0, 0),
+       VREG("gp9",     34, 0, 0),
+       VREG("gp10",    35, 0, 0),
+       VREG("gp11",    36, 0, 0),
+       VREG("gp12",    37, 0, 0),
+       VREG("gp13",    38, 0, 0),
+       VREG("gp14",    39, 0, 0),
+       VREG("gp15",    40, 0, 0),
+       VREG("gp16",    41, 0, 0),
+       VREG("gp17",    42, 0, 0),
+       VREG("s4",      43, 0, 0),
+       VREG("usb2",    44, 0, 0),
+       VREG("wlan2",   45, 0, 0),
+       VREG("xo_out",  46, 0, 0),
+       VREG("lvsw0",   47, 0, 0),
+       VREG("lvsw1",   48, 0, 0),
 };
 
 struct vreg *vreg_get(struct device *dev, const char *id)
@@ -70,7 +92,7 @@ struct vreg *vreg_get(struct device *dev, const char *id)
                if (!strcmp(vregs[n].name, id))
                        return vregs + n;
        }
-       return 0;
+       return ERR_PTR(-ENOENT);
 }
 
 void vreg_put(struct vreg *vreg)
@@ -81,20 +103,39 @@ int vreg_enable(struct vreg *vreg)
 {
        unsigned id = vreg->id;
        unsigned enable = 1;
-       return msm_proc_comm(PCOM_VREG_SWITCH, &id, &enable);
+
+       if (vreg->refcnt == 0)
+               vreg->status = msm_proc_comm(PCOM_VREG_SWITCH, &id, &enable);
+
+       if ((vreg->refcnt < UINT_MAX) && (!vreg->status))
+               vreg->refcnt++;
+
+       return vreg->status;
 }
 
-void vreg_disable(struct vreg *vreg)
+int vreg_disable(struct vreg *vreg)
 {
        unsigned id = vreg->id;
        unsigned enable = 0;
-       msm_proc_comm(PCOM_VREG_SWITCH, &id, &enable);
+
+       if (!vreg->refcnt)
+               return 0;
+
+       if (vreg->refcnt == 1)
+               vreg->status = msm_proc_comm(PCOM_VREG_SWITCH, &id, &enable);
+
+       if (!vreg->status)
+               vreg->refcnt--;
+
+       return vreg->status;
 }
 
 int vreg_set_level(struct vreg *vreg, unsigned mv)
 {
        unsigned id = vreg->id;
-       return msm_proc_comm(PCOM_VREG_SET_LEVEL, &id, &mv);
+
+       vreg->status = msm_proc_comm(PCOM_VREG_SET_LEVEL, &id, &mv);
+       return vreg->status;
 }
 
 #if defined(CONFIG_DEBUG_FS)
@@ -118,24 +159,59 @@ static int vreg_debug_set(void *data, u64 val)
 
 static int vreg_debug_get(void *data, u64 *val)
 {
-       return -ENOSYS;
+       struct vreg *vreg = data;
+
+       if (!vreg->status)
+               *val = 0;
+       else
+               *val = 1;
+
+       return 0;
+}
+
+static int vreg_debug_count_set(void *data, u64 val)
+{
+       struct vreg *vreg = data;
+       if (val > UINT_MAX)
+               val = UINT_MAX;
+       vreg->refcnt = val;
+       return 0;
+}
+
+static int vreg_debug_count_get(void *data, u64 *val)
+{
+       struct vreg *vreg = data;
+
+       *val = vreg->refcnt;
+
+       return 0;
 }
 
 DEFINE_SIMPLE_ATTRIBUTE(vreg_fops, vreg_debug_get, vreg_debug_set, "%llu\n");
+DEFINE_SIMPLE_ATTRIBUTE(vreg_count_fops, vreg_debug_count_get,
+                       vreg_debug_count_set, "%llu\n");
 
 static int __init vreg_debug_init(void)
 {
        struct dentry *dent;
        int n;
+       char name[32];
+       const char *refcnt_name = "_refcnt";
 
        dent = debugfs_create_dir("vreg", 0);
        if (IS_ERR(dent))
                return 0;
 
-       for (n = 0; n < ARRAY_SIZE(vregs); n++)
+       for (n = 0; n < ARRAY_SIZE(vregs); n++) {
                (void) debugfs_create_file(vregs[n].name, 0644,
                                           dent, vregs + n, &vreg_fops);
 
+               strlcpy(name, vregs[n].name, sizeof(name));
+               strlcat(name, refcnt_name, sizeof(name));
+               (void) debugfs_create_file(name, 0644,
+                                          dent, vregs + n, &vreg_count_fops);
+       }
+
        return 0;
 }