mirror of
https://github.com/torvalds/linux.git
synced 2024-12-14 15:13:52 +00:00
0e44106de5
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>
203 lines
4.1 KiB
C
203 lines
4.1 KiB
C
/* 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
|
|
* License version 2, as published by the Free Software Foundation, and
|
|
* may be copied, distributed, and modified under those terms.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
*/
|
|
|
|
#include <linux/kernel.h>
|
|
#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, _status, _refcnt) \
|
|
{ .name = _name, .id = _id, .status = _status, .refcnt = _refcnt }
|
|
|
|
static struct vreg vregs[] = {
|
|
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)
|
|
{
|
|
int n;
|
|
for (n = 0; n < ARRAY_SIZE(vregs); n++) {
|
|
if (!strcmp(vregs[n].name, id))
|
|
return vregs + n;
|
|
}
|
|
return ERR_PTR(-ENOENT);
|
|
}
|
|
|
|
void vreg_put(struct vreg *vreg)
|
|
{
|
|
}
|
|
|
|
int vreg_enable(struct vreg *vreg)
|
|
{
|
|
unsigned id = vreg->id;
|
|
unsigned enable = 1;
|
|
|
|
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;
|
|
}
|
|
|
|
int vreg_disable(struct vreg *vreg)
|
|
{
|
|
unsigned id = vreg->id;
|
|
unsigned enable = 0;
|
|
|
|
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;
|
|
|
|
vreg->status = msm_proc_comm(PCOM_VREG_SET_LEVEL, &id, &mv);
|
|
return vreg->status;
|
|
}
|
|
|
|
#if defined(CONFIG_DEBUG_FS)
|
|
|
|
static int vreg_debug_set(void *data, u64 val)
|
|
{
|
|
struct vreg *vreg = data;
|
|
switch (val) {
|
|
case 0:
|
|
vreg_disable(vreg);
|
|
break;
|
|
case 1:
|
|
vreg_enable(vreg);
|
|
break;
|
|
default:
|
|
vreg_set_level(vreg, val);
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int vreg_debug_get(void *data, u64 *val)
|
|
{
|
|
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++) {
|
|
(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;
|
|
}
|
|
|
|
device_initcall(vreg_debug_init);
|
|
#endif
|