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 /* 230 * sysfs_streq() doesn't need the \n's, but we add them so the strings 231 * will be shared with show_mode(), above. 232 */ 233 if (sysfs_streq(buf, "fast\n")) 234 mode = REGULATOR_MODE_FAST; 235 else if (sysfs_streq(buf, "normal\n")) 236 mode = REGULATOR_MODE_NORMAL; 237 else if (sysfs_streq(buf, "idle\n")) 238 mode = REGULATOR_MODE_IDLE; 239 else if (sysfs_streq(buf, "standby\n")) 240 mode = REGULATOR_MODE_STANDBY; 241 else { 242 dev_err(dev, "Configuring invalid mode\n"); 243 return count; 244 } 245 246 mutex_lock(&data->lock); 247 ret = regulator_set_mode(data->regulator, mode); 248 if (ret == 0) 249 data->mode = mode; 250 else 251 dev_err(dev, "Failed to configure mode: %d\n", ret); 252 mutex_unlock(&data->lock); 253 254 return count; 255 } 256 257 static DEVICE_ATTR(min_microvolts, 0666, show_min_uV, set_min_uV); 258 static DEVICE_ATTR(max_microvolts, 0666, show_max_uV, set_max_uV); 259 static DEVICE_ATTR(min_microamps, 0666, show_min_uA, set_min_uA); 260 static DEVICE_ATTR(max_microamps, 0666, show_max_uA, set_max_uA); 261 static DEVICE_ATTR(mode, 0666, show_mode, set_mode); 262 263 static struct device_attribute *attributes[] = { 264 &dev_attr_min_microvolts, 265 &dev_attr_max_microvolts, 266 &dev_attr_min_microamps, 267 &dev_attr_max_microamps, 268 &dev_attr_mode, 269 }; 270 271 static int regulator_virtual_consumer_probe(struct platform_device *pdev) 272 { 273 char *reg_id = pdev->dev.platform_data; 274 struct virtual_consumer_data *drvdata; 275 int ret, i; 276 277 drvdata = kzalloc(sizeof(struct virtual_consumer_data), GFP_KERNEL); 278 if (drvdata == NULL) { 279 ret = -ENOMEM; 280 goto err; 281 } 282 283 mutex_init(&drvdata->lock); 284 285 drvdata->regulator = regulator_get(&pdev->dev, reg_id); 286 if (IS_ERR(drvdata->regulator)) { 287 ret = PTR_ERR(drvdata->regulator); 288 goto err; 289 } 290 291 for (i = 0; i < ARRAY_SIZE(attributes); i++) { 292 ret = device_create_file(&pdev->dev, attributes[i]); 293 if (ret != 0) 294 goto err; 295 } 296 297 drvdata->mode = regulator_get_mode(drvdata->regulator); 298 299 platform_set_drvdata(pdev, drvdata); 300 301 return 0; 302 303 err: 304 for (i = 0; i < ARRAY_SIZE(attributes); i++) 305 device_remove_file(&pdev->dev, attributes[i]); 306 kfree(drvdata); 307 return ret; 308 } 309 310 static int regulator_virtual_consumer_remove(struct platform_device *pdev) 311 { 312 struct virtual_consumer_data *drvdata = platform_get_drvdata(pdev); 313 int i; 314 315 for (i = 0; i < ARRAY_SIZE(attributes); i++) 316 device_remove_file(&pdev->dev, attributes[i]); 317 if (drvdata->enabled) 318 regulator_disable(drvdata->regulator); 319 regulator_put(drvdata->regulator); 320 321 kfree(drvdata); 322 323 return 0; 324 } 325 326 static struct platform_driver regulator_virtual_consumer_driver = { 327 .probe = regulator_virtual_consumer_probe, 328 .remove = regulator_virtual_consumer_remove, 329 .driver = { 330 .name = "reg-virt-consumer", 331 }, 332 }; 333 334 335 static int __init regulator_virtual_consumer_init(void) 336 { 337 return platform_driver_register(®ulator_virtual_consumer_driver); 338 } 339 module_init(regulator_virtual_consumer_init); 340 341 static void __exit regulator_virtual_consumer_exit(void) 342 { 343 platform_driver_unregister(®ulator_virtual_consumer_driver); 344 } 345 module_exit(regulator_virtual_consumer_exit); 346 347 MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); 348 MODULE_DESCRIPTION("Virtual regulator consumer"); 349 MODULE_LICENSE("GPL"); 350