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