1/* arch/arm/mach-msm/vreg.c 2 * 3 * Copyright (C) 2008 Google, Inc. 4 * Copyright (c) 2009, Code Aurora Forum. All rights reserved. 5 * Author: Brian Swetland <swetland@google.com> 6 * 7 * This software is licensed under the terms of the GNU General Public 8 * License version 2, as published by the Free Software Foundation, and 9 * may be copied, distributed, and modified under those terms. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 */ 17 18#include <linux/kernel.h> 19#include <linux/device.h> 20#include <linux/init.h> 21#include <linux/debugfs.h> 22#include <linux/string.h> 23#include <mach/vreg.h> 24 25#include "proc_comm.h" 26 27struct vreg { 28 const char *name; 29 unsigned id; 30 int status; 31 unsigned refcnt; 32}; 33 34#define VREG(_name, _id, _status, _refcnt) \ 35 { .name = _name, .id = _id, .status = _status, .refcnt = _refcnt } 36 37static struct vreg vregs[] = { 38 VREG("msma", 0, 0, 0), 39 VREG("msmp", 1, 0, 0), 40 VREG("msme1", 2, 0, 0), 41 VREG("msmc1", 3, 0, 0), 42 VREG("msmc2", 4, 0, 0), 43 VREG("gp3", 5, 0, 0), 44 VREG("msme2", 6, 0, 0), 45 VREG("gp4", 7, 0, 0), 46 VREG("gp1", 8, 0, 0), 47 VREG("tcxo", 9, 0, 0), 48 VREG("pa", 10, 0, 0), 49 VREG("rftx", 11, 0, 0), 50 VREG("rfrx1", 12, 0, 0), 51 VREG("rfrx2", 13, 0, 0), 52 VREG("synt", 14, 0, 0), 53 VREG("wlan", 15, 0, 0), 54 VREG("usb", 16, 0, 0), 55 VREG("boost", 17, 0, 0), 56 VREG("mmc", 18, 0, 0), 57 VREG("ruim", 19, 0, 0), 58 VREG("msmc0", 20, 0, 0), 59 VREG("gp2", 21, 0, 0), 60 VREG("gp5", 22, 0, 0), 61 VREG("gp6", 23, 0, 0), 62 VREG("rf", 24, 0, 0), 63 VREG("rf_vco", 26, 0, 0), 64 VREG("mpll", 27, 0, 0), 65 VREG("s2", 28, 0, 0), 66 VREG("s3", 29, 0, 0), 67 VREG("rfubm", 30, 0, 0), 68 VREG("ncp", 31, 0, 0), 69 VREG("gp7", 32, 0, 0), 70 VREG("gp8", 33, 0, 0), 71 VREG("gp9", 34, 0, 0), 72 VREG("gp10", 35, 0, 0), 73 VREG("gp11", 36, 0, 0), 74 VREG("gp12", 37, 0, 0), 75 VREG("gp13", 38, 0, 0), 76 VREG("gp14", 39, 0, 0), 77 VREG("gp15", 40, 0, 0), 78 VREG("gp16", 41, 0, 0), 79 VREG("gp17", 42, 0, 0), 80 VREG("s4", 43, 0, 0), 81 VREG("usb2", 44, 0, 0), 82 VREG("wlan2", 45, 0, 0), 83 VREG("xo_out", 46, 0, 0), 84 VREG("lvsw0", 47, 0, 0), 85 VREG("lvsw1", 48, 0, 0), 86}; 87 88struct vreg *vreg_get(struct device *dev, const char *id) 89{ 90 int n; 91 for (n = 0; n < ARRAY_SIZE(vregs); n++) { 92 if (!strcmp(vregs[n].name, id)) 93 return vregs + n; 94 } 95 return ERR_PTR(-ENOENT); 96} 97 98void vreg_put(struct vreg *vreg) 99{ 100} 101 102int vreg_enable(struct vreg *vreg) 103{ 104 unsigned id = vreg->id; 105 unsigned enable = 1; 106 107 if (vreg->refcnt == 0) 108 vreg->status = msm_proc_comm(PCOM_VREG_SWITCH, &id, &enable); 109 110 if ((vreg->refcnt < UINT_MAX) && (!vreg->status)) 111 vreg->refcnt++; 112 113 return vreg->status; 114} 115 116int vreg_disable(struct vreg *vreg) 117{ 118 unsigned id = vreg->id; 119 unsigned enable = 0; 120 121 if (!vreg->refcnt) 122 return 0; 123 124 if (vreg->refcnt == 1) 125 vreg->status = msm_proc_comm(PCOM_VREG_SWITCH, &id, &enable); 126 127 if (!vreg->status) 128 vreg->refcnt--; 129 130 return vreg->status; 131} 132 133int vreg_set_level(struct vreg *vreg, unsigned mv) 134{ 135 unsigned id = vreg->id; 136 137 vreg->status = msm_proc_comm(PCOM_VREG_SET_LEVEL, &id, &mv); 138 return vreg->status; 139} 140 141#if defined(CONFIG_DEBUG_FS) 142 143static int vreg_debug_set(void *data, u64 val) 144{ 145 struct vreg *vreg = data; 146 switch (val) { 147 case 0: 148 vreg_disable(vreg); 149 break; 150 case 1: 151 vreg_enable(vreg); 152 break; 153 default: 154 vreg_set_level(vreg, val); 155 break; 156 } 157 return 0; 158} 159 160static int vreg_debug_get(void *data, u64 *val) 161{ 162 struct vreg *vreg = data; 163 164 if (!vreg->status) 165 *val = 0; 166 else 167 *val = 1; 168 169 return 0; 170} 171 172static int vreg_debug_count_set(void *data, u64 val) 173{ 174 struct vreg *vreg = data; 175 if (val > UINT_MAX) 176 val = UINT_MAX; 177 vreg->refcnt = val; 178 return 0; 179} 180 181static int vreg_debug_count_get(void *data, u64 *val) 182{ 183 struct vreg *vreg = data; 184 185 *val = vreg->refcnt; 186 187 return 0; 188} 189 190DEFINE_SIMPLE_ATTRIBUTE(vreg_fops, vreg_debug_get, vreg_debug_set, "%llu\n"); 191DEFINE_SIMPLE_ATTRIBUTE(vreg_count_fops, vreg_debug_count_get, 192 vreg_debug_count_set, "%llu\n"); 193 194static int __init vreg_debug_init(void) 195{ 196 struct dentry *dent; 197 int n; 198 char name[32]; 199 const char *refcnt_name = "_refcnt"; 200 201 dent = debugfs_create_dir("vreg", 0); 202 if (IS_ERR(dent)) 203 return 0; 204 205 for (n = 0; n < ARRAY_SIZE(vregs); n++) { 206 (void) debugfs_create_file(vregs[n].name, 0644, 207 dent, vregs + n, &vreg_fops); 208 209 strlcpy(name, vregs[n].name, sizeof(name)); 210 strlcat(name, refcnt_name, sizeof(name)); 211 (void) debugfs_create_file(name, 0644, 212 dent, vregs + n, &vreg_count_fops); 213 } 214 215 return 0; 216} 217 218device_initcall(vreg_debug_init); 219#endif 220