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