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 device *dev, 31 struct virtual_consumer_data *data) 32 { 33 int ret; 34 35 if (data->min_uV && data->max_uV 36 && data->min_uV <= data->max_uV) { 37 dev_dbg(dev, "Requesting %d-%duV\n", 38 data->min_uV, data->max_uV); 39 ret = regulator_set_voltage(data->regulator, 40 data->min_uV, data->max_uV); 41 if (ret != 0) { 42 dev_err(dev, 43 "regulator_set_voltage() failed: %d\n", ret); 44 return; 45 } 46 } 47 48 if (data->min_uV && data->max_uV && !data->enabled) { 49 dev_dbg(dev, "Enabling regulator\n"); 50 ret = regulator_enable(data->regulator); 51 if (ret == 0) 52 data->enabled = 1; 53 else 54 dev_err(dev, "regulator_enable() failed: %d\n", 55 ret); 56 } 57 58 if (!(data->min_uV && data->max_uV) && data->enabled) { 59 dev_dbg(dev, "Disabling regulator\n"); 60 ret = regulator_disable(data->regulator); 61 if (ret == 0) 62 data->enabled = 0; 63 else 64 dev_err(dev, "regulator_disable() failed: %d\n", 65 ret); 66 } 67 } 68 69 static void update_current_limit_constraints(struct device *dev, 70 struct virtual_consumer_data *data) 71 { 72 int ret; 73 74 if (data->max_uA 75 && data->min_uA <= data->max_uA) { 76 dev_dbg(dev, "Requesting %d-%duA\n", 77 data->min_uA, data->max_uA); 78 ret = regulator_set_current_limit(data->regulator, 79 data->min_uA, data->max_uA); 80 if (ret != 0) { 81 dev_err(dev, 82 "regulator_set_current_limit() failed: %d\n", 83 ret); 84 return; 85 } 86 } 87 88 if (data->max_uA && !data->enabled) { 89 dev_dbg(dev, "Enabling regulator\n"); 90 ret = regulator_enable(data->regulator); 91 if (ret == 0) 92 data->enabled = 1; 93 else 94 dev_err(dev, "regulator_enable() failed: %d\n", 95 ret); 96 } 97 98 if (!(data->min_uA && data->max_uA) && data->enabled) { 99 dev_dbg(dev, "Disabling regulator\n"); 100 ret = regulator_disable(data->regulator); 101 if (ret == 0) 102 data->enabled = 0; 103 else 104 dev_err(dev, "regulator_disable() failed: %d\n", 105 ret); 106 } 107 } 108 109 static ssize_t show_min_uV(struct device *dev, 110 struct device_attribute *attr, char *buf) 111 { 112 struct virtual_consumer_data *data = dev_get_drvdata(dev); 113 return sprintf(buf, "%d\n", data->min_uV); 114 } 115 116 static ssize_t set_min_uV(struct device *dev, struct device_attribute *attr, 117 const char *buf, size_t count) 118 { 119 struct virtual_consumer_data *data = dev_get_drvdata(dev); 120 long val; 121 122 if (strict_strtol(buf, 10, &val) != 0) 123 return count; 124 125 mutex_lock(&data->lock); 126 127 data->min_uV = val; 128 update_voltage_constraints(dev, data); 129 130 mutex_unlock(&data->lock); 131 132 return count; 133 } 134 135 static ssize_t show_max_uV(struct device *dev, 136 struct device_attribute *attr, char *buf) 137 { 138 struct virtual_consumer_data *data = dev_get_drvdata(dev); 139 return sprintf(buf, "%d\n", data->max_uV); 140 } 141 142 static ssize_t set_max_uV(struct device *dev, struct device_attribute *attr, 143 const char *buf, size_t count) 144 { 145 struct virtual_consumer_data *data = dev_get_drvdata(dev); 146 long val; 147 148 if (strict_strtol(buf, 10, &val) != 0) 149 return count; 150 151 mutex_lock(&data->lock); 152 153 data->max_uV = val; 154 update_voltage_constraints(dev, data); 155 156 mutex_unlock(&data->lock); 157 158 return count; 159 } 160 161 static ssize_t show_min_uA(struct device *dev, 162 struct device_attribute *attr, char *buf) 163 { 164 struct virtual_consumer_data *data = dev_get_drvdata(dev); 165 return sprintf(buf, "%d\n", data->min_uA); 166 } 167 168 static ssize_t set_min_uA(struct device *dev, struct device_attribute *attr, 169 const char *buf, size_t count) 170 { 171 struct virtual_consumer_data *data = dev_get_drvdata(dev); 172 long val; 173 174 if (strict_strtol(buf, 10, &val) != 0) 175 return count; 176 177 mutex_lock(&data->lock); 178 179 data->min_uA = val; 180 update_current_limit_constraints(dev, data); 181 182 mutex_unlock(&data->lock); 183 184 return count; 185 } 186 187 static ssize_t show_max_uA(struct device *dev, 188 struct device_attribute *attr, char *buf) 189 { 190 struct virtual_consumer_data *data = dev_get_drvdata(dev); 191 return sprintf(buf, "%d\n", data->max_uA); 192 } 193 194 static ssize_t set_max_uA(struct device *dev, struct device_attribute *attr, 195 const char *buf, size_t count) 196 { 197 struct virtual_consumer_data *data = dev_get_drvdata(dev); 198 long val; 199 200 if (strict_strtol(buf, 10, &val) != 0) 201 return count; 202 203 mutex_lock(&data->lock); 204 205 data->max_uA = val; 206 update_current_limit_constraints(dev, data); 207 208 mutex_unlock(&data->lock); 209 210 return count; 211 } 212 213 static ssize_t show_mode(struct device *dev, 214 struct device_attribute *attr, char *buf) 215 { 216 struct virtual_consumer_data *data = dev_get_drvdata(dev); 217 218 switch (data->mode) { 219 case REGULATOR_MODE_FAST: 220 return sprintf(buf, "fast\n"); 221 case REGULATOR_MODE_NORMAL: 222 return sprintf(buf, "normal\n"); 223 case REGULATOR_MODE_IDLE: 224 return sprintf(buf, "idle\n"); 225 case REGULATOR_MODE_STANDBY: 226 return sprintf(buf, "standby\n"); 227 default: 228 return sprintf(buf, "unknown\n"); 229 } 230 } 231 232 static ssize_t set_mode(struct device *dev, struct device_attribute *attr, 233 const char *buf, size_t count) 234 { 235 struct virtual_consumer_data *data = dev_get_drvdata(dev); 236 unsigned int mode; 237 int ret; 238 239 /* 240 * sysfs_streq() doesn't need the \n's, but we add them so the strings 241 * will be shared with show_mode(), above. 242 */ 243 if (sysfs_streq(buf, "fast\n")) 244 mode = REGULATOR_MODE_FAST; 245 else if (sysfs_streq(buf, "normal\n")) 246 mode = REGULATOR_MODE_NORMAL; 247 else if (sysfs_streq(buf, "idle\n")) 248 mode = REGULATOR_MODE_IDLE; 249 else if (sysfs_streq(buf, "standby\n")) 250 mode = REGULATOR_MODE_STANDBY; 251 else { 252 dev_err(dev, "Configuring invalid mode\n"); 253 return count; 254 } 255 256 mutex_lock(&data->lock); 257 ret = regulator_set_mode(data->regulator, mode); 258 if (ret == 0) 259 data->mode = mode; 260 else 261 dev_err(dev, "Failed to configure mode: %d\n", ret); 262 mutex_unlock(&data->lock); 263 264 return count; 265 } 266 267 static DEVICE_ATTR(min_microvolts, 0666, show_min_uV, set_min_uV); 268 static DEVICE_ATTR(max_microvolts, 0666, show_max_uV, set_max_uV); 269 static DEVICE_ATTR(min_microamps, 0666, show_min_uA, set_min_uA); 270 static DEVICE_ATTR(max_microamps, 0666, show_max_uA, set_max_uA); 271 static DEVICE_ATTR(mode, 0666, show_mode, set_mode); 272 273 static struct device_attribute *attributes[] = { 274 &dev_attr_min_microvolts, 275 &dev_attr_max_microvolts, 276 &dev_attr_min_microamps, 277 &dev_attr_max_microamps, 278 &dev_attr_mode, 279 }; 280 281 static int regulator_virtual_consumer_probe(struct platform_device *pdev) 282 { 283 char *reg_id = pdev->dev.platform_data; 284 struct virtual_consumer_data *drvdata; 285 int ret, i; 286 287 drvdata = kzalloc(sizeof(struct virtual_consumer_data), GFP_KERNEL); 288 if (drvdata == NULL) { 289 return -ENOMEM; 290 } 291 292 mutex_init(&drvdata->lock); 293 294 drvdata->regulator = regulator_get(&pdev->dev, reg_id); 295 if (IS_ERR(drvdata->regulator)) { 296 ret = PTR_ERR(drvdata->regulator); 297 dev_err(&pdev->dev, "Failed to obtain supply '%s': %d\n", 298 reg_id, ret); 299 goto err; 300 } 301 302 for (i = 0; i < ARRAY_SIZE(attributes); i++) { 303 ret = device_create_file(&pdev->dev, attributes[i]); 304 if (ret != 0) { 305 dev_err(&pdev->dev, "Failed to create attr %d: %d\n", 306 i, ret); 307 goto err_regulator; 308 } 309 } 310 311 drvdata->mode = regulator_get_mode(drvdata->regulator); 312 313 platform_set_drvdata(pdev, drvdata); 314 315 return 0; 316 317 err_regulator: 318 regulator_put(drvdata->regulator); 319 err: 320 for (i = 0; i < ARRAY_SIZE(attributes); i++) 321 device_remove_file(&pdev->dev, attributes[i]); 322 kfree(drvdata); 323 return ret; 324 } 325 326 static int regulator_virtual_consumer_remove(struct platform_device *pdev) 327 { 328 struct virtual_consumer_data *drvdata = platform_get_drvdata(pdev); 329 int i; 330 331 for (i = 0; i < ARRAY_SIZE(attributes); i++) 332 device_remove_file(&pdev->dev, attributes[i]); 333 if (drvdata->enabled) 334 regulator_disable(drvdata->regulator); 335 regulator_put(drvdata->regulator); 336 337 kfree(drvdata); 338 339 return 0; 340 } 341 342 static struct platform_driver regulator_virtual_consumer_driver = { 343 .probe = regulator_virtual_consumer_probe, 344 .remove = regulator_virtual_consumer_remove, 345 .driver = { 346 .name = "reg-virt-consumer", 347 }, 348 }; 349 350 351 static int __init regulator_virtual_consumer_init(void) 352 { 353 return platform_driver_register(®ulator_virtual_consumer_driver); 354 } 355 module_init(regulator_virtual_consumer_init); 356 357 static void __exit regulator_virtual_consumer_exit(void) 358 { 359 platform_driver_unregister(®ulator_virtual_consumer_driver); 360 } 361 module_exit(regulator_virtual_consumer_exit); 362 363 MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); 364 MODULE_DESCRIPTION("Virtual regulator consumer"); 365 MODULE_LICENSE("GPL"); 366 MODULE_ALIAS("platform:reg-virt-consumer"); 367