linux/drivers/regulator/virtual.c
<<
>>
Prefs
   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
  20struct 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
  31static 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
  70static 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
 110static 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
 117static 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
 136static 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
 143static 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
 162static 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
 169static 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
 188static 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
 195static 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
 214static 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
 233static 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
 268static DEVICE_ATTR(min_microvolts, 0666, show_min_uV, set_min_uV);
 269static DEVICE_ATTR(max_microvolts, 0666, show_max_uV, set_max_uV);
 270static DEVICE_ATTR(min_microamps, 0666, show_min_uA, set_min_uA);
 271static DEVICE_ATTR(max_microamps, 0666, show_max_uA, set_max_uA);
 272static DEVICE_ATTR(mode, 0666, show_mode, set_mode);
 273
 274static 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
 283static const struct attribute_group regulator_virtual_attr_group = {
 284        .attrs  = regulator_virtual_attributes,
 285};
 286
 287static 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                                 &regulator_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
 321err_regulator:
 322        regulator_put(drvdata->regulator);
 323err:
 324        kfree(drvdata);
 325        return ret;
 326}
 327
 328static 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, &regulator_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
 345static 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
 354static int __init regulator_virtual_consumer_init(void)
 355{
 356        return platform_driver_register(&regulator_virtual_consumer_driver);
 357}
 358module_init(regulator_virtual_consumer_init);
 359
 360static void __exit regulator_virtual_consumer_exit(void)
 361{
 362        platform_driver_unregister(&regulator_virtual_consumer_driver);
 363}
 364module_exit(regulator_virtual_consumer_exit);
 365
 366MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
 367MODULE_DESCRIPTION("Virtual regulator consumer");
 368MODULE_LICENSE("GPL");
 369MODULE_ALIAS("platform:reg-virt-consumer");
 370