summaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorMatt Wilson <mtwilson@quicinc.com>2009-06-29 14:13:04 -0500
committerDaniel Walker <dwalker@codeaurora.org>2010-05-12 09:14:40 -0700
commit0e44106de5adffc32e0a9294ed406f20d9a3f38d (patch)
tree0d7212a1df34f46fdf882fc288c4ec133a875e93 /arch
parent4eab62519f8f58aa5f72787877c459925399d617 (diff)
downloadlinux-0e44106de5adffc32e0a9294ed406f20d9a3f38d.tar.bz2
arm: msm: add vreg reference count
Support independent enable and disable by clients for common vreg. First enable switches on and last disable switches off. This change has no check for voltage level so clients must agree on level for common vreg. Signed-off-by: Matthew Wilson <mtwilson@quicinc.com>
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/mach-msm/vreg.c115
1 files changed, 79 insertions, 36 deletions
diff --git a/arch/arm/mach-msm/vreg.c b/arch/arm/mach-msm/vreg.c
index 8b0f7b2fd8f7..63db0b3ece53 100644
--- a/arch/arm/mach-msm/vreg.c
+++ b/arch/arm/mach-msm/vreg.c
@@ -19,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"
@@ -27,43 +28,44 @@ struct vreg {
const char *name;
unsigned id;
int status;
+ unsigned refcnt;
};
-#define VREG(_name, _id, _status) \
- { .name = _name, .id = _id, .status = _status }
+#define VREG(_name, _id, _status, _refcnt) \
+ { .name = _name, .id = _id, .status = _status, .refcnt = _refcnt }
static struct vreg vregs[] = {
- VREG("msma", 0, 0),
- VREG("msmp", 1, 0),
- VREG("msme1", 2, 0),
- VREG("msmc1", 3, 0),
- VREG("msmc2", 4, 0),
- VREG("gp3", 5, 0),
- VREG("msme2", 6, 0),
- VREG("gp4", 7, 0),
- VREG("gp1", 8, 0),
- VREG("tcxo", 9, 0),
- VREG("pa", 10, 0),
- VREG("rftx", 11, 0),
- VREG("rfrx1", 12, 0),
- VREG("rfrx2", 13, 0),
- VREG("synt", 14, 0),
- VREG("wlan", 15, 0),
- VREG("usb", 16, 0),
- VREG("boost", 17, 0),
- VREG("mmc", 18, 0),
- VREG("ruim", 19, 0),
- VREG("msmc0", 20, 0),
- VREG("gp2", 21, 0),
- VREG("gp5", 22, 0),
- VREG("gp6", 23, 0),
- VREG("rf", 24, 0),
- VREG("rf_vco", 26, 0),
- VREG("mpll", 27, 0),
- VREG("s2", 28, 0),
- VREG("s3", 29, 0),
- VREG("rfubm", 30, 0),
- VREG("ncp", 31, 0),
+ 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),
};
struct vreg *vreg_get(struct device *dev, const char *id)
@@ -85,7 +87,12 @@ int vreg_enable(struct vreg *vreg)
unsigned id = vreg->id;
unsigned enable = 1;
- vreg->status = 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;
}
@@ -94,7 +101,15 @@ int vreg_disable(struct vreg *vreg)
unsigned id = vreg->id;
unsigned enable = 0;
- vreg->status = 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;
}
@@ -137,21 +152,49 @@ static int vreg_debug_get(void *data, u64 *val)
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;
}