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 #include #include +#include #include #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; }