提交 0e44106d 编写于 作者: M Matt Wilson 提交者: Daniel Walker

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: NMatthew Wilson <mtwilson@quicinc.com>
上级 4eab6251
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <linux/device.h> #include <linux/device.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/debugfs.h> #include <linux/debugfs.h>
#include <linux/string.h>
#include <mach/vreg.h> #include <mach/vreg.h>
#include "proc_comm.h" #include "proc_comm.h"
...@@ -27,43 +28,44 @@ struct vreg { ...@@ -27,43 +28,44 @@ struct vreg {
const char *name; const char *name;
unsigned id; unsigned id;
int status; int status;
unsigned refcnt;
}; };
#define VREG(_name, _id, _status) \ #define VREG(_name, _id, _status, _refcnt) \
{ .name = _name, .id = _id, .status = _status } { .name = _name, .id = _id, .status = _status, .refcnt = _refcnt }
static struct vreg vregs[] = { static struct vreg vregs[] = {
VREG("msma", 0, 0), VREG("msma", 0, 0, 0),
VREG("msmp", 1, 0), VREG("msmp", 1, 0, 0),
VREG("msme1", 2, 0), VREG("msme1", 2, 0, 0),
VREG("msmc1", 3, 0), VREG("msmc1", 3, 0, 0),
VREG("msmc2", 4, 0), VREG("msmc2", 4, 0, 0),
VREG("gp3", 5, 0), VREG("gp3", 5, 0, 0),
VREG("msme2", 6, 0), VREG("msme2", 6, 0, 0),
VREG("gp4", 7, 0), VREG("gp4", 7, 0, 0),
VREG("gp1", 8, 0), VREG("gp1", 8, 0, 0),
VREG("tcxo", 9, 0), VREG("tcxo", 9, 0, 0),
VREG("pa", 10, 0), VREG("pa", 10, 0, 0),
VREG("rftx", 11, 0), VREG("rftx", 11, 0, 0),
VREG("rfrx1", 12, 0), VREG("rfrx1", 12, 0, 0),
VREG("rfrx2", 13, 0), VREG("rfrx2", 13, 0, 0),
VREG("synt", 14, 0), VREG("synt", 14, 0, 0),
VREG("wlan", 15, 0), VREG("wlan", 15, 0, 0),
VREG("usb", 16, 0), VREG("usb", 16, 0, 0),
VREG("boost", 17, 0), VREG("boost", 17, 0, 0),
VREG("mmc", 18, 0), VREG("mmc", 18, 0, 0),
VREG("ruim", 19, 0), VREG("ruim", 19, 0, 0),
VREG("msmc0", 20, 0), VREG("msmc0", 20, 0, 0),
VREG("gp2", 21, 0), VREG("gp2", 21, 0, 0),
VREG("gp5", 22, 0), VREG("gp5", 22, 0, 0),
VREG("gp6", 23, 0), VREG("gp6", 23, 0, 0),
VREG("rf", 24, 0), VREG("rf", 24, 0, 0),
VREG("rf_vco", 26, 0), VREG("rf_vco", 26, 0, 0),
VREG("mpll", 27, 0), VREG("mpll", 27, 0, 0),
VREG("s2", 28, 0), VREG("s2", 28, 0, 0),
VREG("s3", 29, 0), VREG("s3", 29, 0, 0),
VREG("rfubm", 30, 0), VREG("rfubm", 30, 0, 0),
VREG("ncp", 31, 0), VREG("ncp", 31, 0, 0),
}; };
struct vreg *vreg_get(struct device *dev, const char *id) struct vreg *vreg_get(struct device *dev, const char *id)
...@@ -85,7 +87,12 @@ int vreg_enable(struct vreg *vreg) ...@@ -85,7 +87,12 @@ int vreg_enable(struct vreg *vreg)
unsigned id = vreg->id; unsigned id = vreg->id;
unsigned enable = 1; 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; return vreg->status;
} }
...@@ -94,7 +101,15 @@ int vreg_disable(struct vreg *vreg) ...@@ -94,7 +101,15 @@ int vreg_disable(struct vreg *vreg)
unsigned id = vreg->id; unsigned id = vreg->id;
unsigned enable = 0; 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; return vreg->status;
} }
...@@ -137,21 +152,49 @@ static int vreg_debug_get(void *data, u64 *val) ...@@ -137,21 +152,49 @@ static int vreg_debug_get(void *data, u64 *val)
return 0; 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_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) static int __init vreg_debug_init(void)
{ {
struct dentry *dent; struct dentry *dent;
int n; int n;
char name[32];
const char *refcnt_name = "_refcnt";
dent = debugfs_create_dir("vreg", 0); dent = debugfs_create_dir("vreg", 0);
if (IS_ERR(dent)) if (IS_ERR(dent))
return 0; 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, (void) debugfs_create_file(vregs[n].name, 0644,
dent, vregs + n, &vreg_fops); 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; return 0;
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册