1 /* 2 * reg-virtual-consumer.c 3 * 4 * Copyright 2008 Wolfson Microelectronics PLC. 5 * 6 * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> 7 * 8 * This program is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU General Public License as 10 * published by the Free Software Foundation; either version 2 of the 11 * License, or (at your option) any later version. 12 */ 13 14 #include <linux/err.h> 15 #include <linux/mutex.h> 16 #include <linux/platform_device.h> 17 #include <linux/regulator/consumer.h> 18 19 struct virtual_consumer_data { 20 struct mutex lock; 21 struct regulator *regulator; 22 int enabled; 23 int min_uV; 24 int max_uV; 25 int min_uA; 26 int max_uA; 27 unsigned int mode; 28 }; 29 30 static void update_voltage_constraints(struct virtual_consumer_data *data) 31 { 32 int ret; 33 34 if (data->min_uV && data->max_uV 35 && data->min_uV <= data->max_uV) { 36 ret = regulator_set_voltage(data->regulator, 37 data->min_uV, data->max_uV); 38 if (ret != 0) { 39 printk(KERN_ERR "regulator_set_voltage() failed: %d\n", 40 ret); 41 return; 42 } 43 } 44 45 if (data->min_uV && data->max_uV && !data->enabled) { 46 ret = regulator_enable(data->regulator); 47 if (ret == 0) 48 data->enabled = 1; 49 else 50 printk(KERN_ERR "regulator_enable() failed: %d\n", 51 ret); 52 } 53 54 if (!(data->min_uV && data->max_uV) && data->enabled) { 55 ret = regulator_disable(data->regulator); 56 if (ret == 0) 57 data->enabled = 0; 58 else 59 printk(KERN_ERR "regulator_disable() failed: %d\n", 60 ret); 61 } 62 } 63 64 static void update_current_limit_constraints(struct virtual_consumer_data 65 *data) 66 { 67 int ret; 68 69 if (data->max_uA 70 && data->min_uA <= data->max_uA) { 71 ret = regulator_set_current_limit(data->regulator, 72 data->min_uA, data->max_uA); 73 if (ret != 0) { 74 pr_err("regulator_set_current_limit() failed: %d\n", 75 ret); 76 return; 77 } 78 } 79 80 if (data->max_uA && !data->enabled) { 81 ret = regulator_enable(data->regulator); 82 if (ret == 0) 83 data->enabled = 1; 84 else 85 printk(KERN_ERR "regulator_enable() failed: %d\n", 86 ret); 87 } 88 89 if (!(data->min_uA && data->max_uA) && data->enabled) { 90 ret = regulator_disable(data->regulator); 91 if (ret == 0) 92 data->enabled = 0; 93 else 94 printk(KERN_ERR "regulator_disable() failed: %d\n", 95 ret); 96 } 97 } 98 99 static ssize_t show_min_uV(struct device *dev, 100 struct device_attribute *attr, char *buf) 101 { 102 struct virtual_consumer_data *data = dev_get_drvdata(dev); 103 return sprintf(buf, "%d\n", data->min_uV); 104 } 105 106 static ssize_t set_min_uV(struct device *dev, struct device_attribute *attr, 107 const char *buf, size_t count) 108 { 109 struct virtual_consumer_data *data = dev_get_drvdata(dev); 110 long val; 111 112 if (strict_strtol(buf, 10, &val) != 0) 113 return count; 114 115 mutex_lock(&data->lock); 116 117 data->min_uV = val; 118 update_voltage_constraints(data); 119 120 mutex_unlock(&data->lock); 121 122 return count; 123 } 124 125 static ssize_t show_max_uV(struct device *dev, 126 struct device_attribute *attr, char *buf) 127 { 128 struct virtual_consumer_data *data = dev_get_drvdata(dev); 129 return sprintf(buf, "%d\n", data->max_uV); 130 } 131 132 static ssize_t set_max_uV(struct device *dev, struct device_attribute *attr, 133 const char *buf, size_t count) 134 { 135 struct virtual_consumer_data *data = dev_get_drvdata(dev); 136 long val; 137 138 if (strict_strtol(buf, 10, &val) != 0) 139 return count; 140 141 mutex_lock(&data->lock); 142 143 data->max_uV = val; 144 update_voltage_constraints(data); 145 146 mutex_unlock(&data->lock); 147 148 return count; 149 } 150 151 static ssize_t show_min_uA(struct device *dev, 152 struct device_attribute *attr, char *buf) 153 { 154 struct virtual_consumer_data *data = dev_get_drvdata(dev); 155 return sprintf(buf, "%d\n", data->min_uA); 156 } 157 158 static ssize_t set_min_uA(struct device *dev, struct device_attribute *attr, 159 const char *buf, size_t count) 160 { 161 struct virtual_consumer_data *data = dev_get_drvdata(dev); 162 long val; 163 164 if (strict_strtol(buf, 10, &val) != 0) 165 return count; 166 167 mutex_lock(&data->lock); 168 169 data->min_uA = val; 170 update_current_limit_constraints(data); 171 172 mutex_unlock(&data->lock); 173 174 return count; 175 } 176 177 static ssize_t show_max_uA(struct device *dev, 178 struct device_attribute *attr, char *buf) 179 { 180 struct virtual_consumer_data *data = dev_get_drvdata(dev); 181 return sprintf(buf, "%d\n", data->max_uA); 182 } 183 184 static ssize_t set_max_uA(struct device *dev, struct device_attribute *attr, 185 const char *buf, size_t count) 186 { 187 struct virtual_consumer_data *data = dev_get_drvdata(dev); 188 long val; 189 190 if (strict_strtol(buf, 10, &val) != 0) 191 return count; 192 193 mutex_lock(&data->lock); 194 195 data->max_uA = val; 196 update_current_limit_constraints(data); 197 198 mutex_unlock(&data->lock); 199 200 return count; 201 } 202 203 static ssize_t show_mode(struct device *dev, 204 struct device_attribute *attr, char *buf) 205 { 206 struct virtual_consumer_data *data = dev_get_drvdata(dev); 207 208 switch (data->mode) { 209 case REGULATOR_MODE_FAST: 210 return sprintf(buf, "fast\n"); 211 case REGULATOR_MODE_NORMAL: 212 return sprintf(buf, "normal\n"); 213 case REGULATOR_MODE_IDLE: 214 return sprintf(buf, "idle\n"); 215 case REGULATOR_MODE_STANDBY: 216 return sprintf(buf, "standby\n"); 217 default: 218 return sprintf(buf, "unknown\n"); 219 } 220 } 221 222 static ssize_t set_mode(struct device *dev, struct device_attribute *attr, 223 const char *buf, size_t count) 224 { 225 struct virtual_consumer_data *data = dev_get_drvdata(dev); 226 unsigned int mode; 227 int ret; 228 229 if (strncmp(buf, "fast", strlen("fast")) == 0) 230 mode = REGULATOR_MODE_FAST; 231 else if (strncmp(buf, "normal", strlen("normal")) == 0) 232 mode = REGULATOR_MODE_NORMAL; 233 else if (strncmp(buf, "idle", strlen("idle")) == 0) 234 mode = REGULATOR_MODE_IDLE; 235 else if (strncmp(buf, "standby", strlen("standby")) == 0) 236 mode = REGULATOR_MODE_STANDBY; 237 else { 238 dev_err(dev, "Configuring invalid mode\n"); 239 return count; 240 } 241 242 mutex_lock(&data->lock); 243 ret = regulator_set_mode(data->regulator, mode); 244 if (ret == 0) 245 data->mode = mode; 246 else 247 dev_err(dev, "Failed to configure mode: %d\n", ret); 248 mutex_unlock(&data->lock); 249 250 return count; 251 } 252 253 static DEVICE_ATTR(min_microvolts, 0666, show_min_uV, set_min_uV); 254 static DEVICE_ATTR(max_microvolts, 0666, show_max_uV, set_max_uV); 255 static DEVICE_ATTR(min_microamps, 0666, show_min_uA, set_min_uA); 256 static DEVICE_ATTR(max_microamps, 0666, show_max_uA, set_max_uA); 257 static DEVICE_ATTR(mode, 0666, show_mode, set_mode); 258 259 struct device_attribute *attributes[] = { 260 &dev_attr_min_microvolts, 261 &dev_attr_max_microvolts, 262 &dev_attr_min_microamps, 263 &dev_attr_max_microamps, 264 &dev_attr_mode, 265 }; 266 267 static int regulator_virtual_consumer_probe(struct platform_device *pdev) 268 { 269 char *reg_id = pdev->dev.platform_data; 270 struct virtual_consumer_data *drvdata; 271 int ret, i; 272 273 drvdata = kzalloc(sizeof(struct virtual_consumer_data), GFP_KERNEL); 274 if (drvdata == NULL) { 275 ret = -ENOMEM; 276 goto err; 277 } 278 279 mutex_init(&drvdata->lock); 280 281 drvdata->regulator = regulator_get(&pdev->dev, reg_id); 282 if (IS_ERR(drvdata->regulator)) { 283 ret = PTR_ERR(drvdata->regulator); 284 goto err; 285 } 286 287 for (i = 0; i < ARRAY_SIZE(attributes); i++) { 288 ret = device_create_file(&pdev->dev, attributes[i]); 289 if (ret != 0) 290 goto err; 291 } 292 293 drvdata->mode = regulator_get_mode(drvdata->regulator); 294 295 platform_set_drvdata(pdev, drvdata); 296 297 return 0; 298 299 err: 300 for (i = 0; i < ARRAY_SIZE(attributes); i++) 301 device_remove_file(&pdev->dev, attributes[i]); 302 kfree(drvdata); 303 return ret; 304 } 305 306 static int regulator_virtual_consumer_remove(struct platform_device *pdev) 307 { 308 struct virtual_consumer_data *drvdata = platform_get_drvdata(pdev); 309 int i; 310 311 for (i = 0; i < ARRAY_SIZE(attributes); i++) 312 device_remove_file(&pdev->dev, attributes[i]); 313 if (drvdata->enabled) 314 regulator_disable(drvdata->regulator); 315 regulator_put(drvdata->regulator); 316 317 kfree(drvdata); 318 319 return 0; 320 } 321 322 static struct platform_driver regulator_virtual_consumer_driver = { 323 .probe = regulator_virtual_consumer_probe, 324 .remove = regulator_virtual_consumer_remove, 325 .driver = { 326 .name = "reg-virt-consumer", 327 }, 328 }; 329 330 331 static int __init regulator_virtual_consumer_init(void) 332 { 333 return platform_driver_register(®ulator_virtual_consumer_driver); 334 } 335 module_init(regulator_virtual_consumer_init); 336 337 static void __exit regulator_virtual_consumer_exit(void) 338 { 339 platform_driver_unregister(®ulator_virtual_consumer_driver); 340 } 341 module_exit(regulator_virtual_consumer_exit); 342 343 MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); 344 MODULE_DESCRIPTION("Virtual regulator consumer"); 345 MODULE_LICENSE("GPL"); 346