1414c70cbSLiam Girdwood /* 2414c70cbSLiam Girdwood * core.c -- Voltage/Current Regulator framework. 3414c70cbSLiam Girdwood * 4414c70cbSLiam Girdwood * Copyright 2007, 2008 Wolfson Microelectronics PLC. 5a5766f11SLiam Girdwood * Copyright 2008 SlimLogic Ltd. 6414c70cbSLiam Girdwood * 7a5766f11SLiam Girdwood * Author: Liam Girdwood <lrg@slimlogic.co.uk> 8414c70cbSLiam Girdwood * 9414c70cbSLiam Girdwood * This program is free software; you can redistribute it and/or modify it 10414c70cbSLiam Girdwood * under the terms of the GNU General Public License as published by the 11414c70cbSLiam Girdwood * Free Software Foundation; either version 2 of the License, or (at your 12414c70cbSLiam Girdwood * option) any later version. 13414c70cbSLiam Girdwood * 14414c70cbSLiam Girdwood */ 15414c70cbSLiam Girdwood 16414c70cbSLiam Girdwood #include <linux/kernel.h> 17414c70cbSLiam Girdwood #include <linux/init.h> 181130e5b3SMark Brown #include <linux/debugfs.h> 19414c70cbSLiam Girdwood #include <linux/device.h> 205a0e3ad6STejun Heo #include <linux/slab.h> 21f21e0e81SMark Brown #include <linux/async.h> 22414c70cbSLiam Girdwood #include <linux/err.h> 23414c70cbSLiam Girdwood #include <linux/mutex.h> 24414c70cbSLiam Girdwood #include <linux/suspend.h> 2531aae2beSMark Brown #include <linux/delay.h> 2669511a45SRajendra Nayak #include <linux/of.h> 2765b19ce6SMark Brown #include <linux/regmap.h> 2869511a45SRajendra Nayak #include <linux/regulator/of_regulator.h> 29414c70cbSLiam Girdwood #include <linux/regulator/consumer.h> 30414c70cbSLiam Girdwood #include <linux/regulator/driver.h> 31414c70cbSLiam Girdwood #include <linux/regulator/machine.h> 3265602c32SPaul Gortmaker #include <linux/module.h> 33414c70cbSLiam Girdwood 3402fa3ec0SMark Brown #define CREATE_TRACE_POINTS 3502fa3ec0SMark Brown #include <trace/events/regulator.h> 3602fa3ec0SMark Brown 3734abbd68SMark Brown #include "dummy.h" 3834abbd68SMark Brown 397d51a0dbSMark Brown #define rdev_crit(rdev, fmt, ...) \ 407d51a0dbSMark Brown pr_crit("%s: " fmt, rdev_get_name(rdev), ##__VA_ARGS__) 415da84fd9SJoe Perches #define rdev_err(rdev, fmt, ...) \ 425da84fd9SJoe Perches pr_err("%s: " fmt, rdev_get_name(rdev), ##__VA_ARGS__) 435da84fd9SJoe Perches #define rdev_warn(rdev, fmt, ...) \ 445da84fd9SJoe Perches pr_warn("%s: " fmt, rdev_get_name(rdev), ##__VA_ARGS__) 455da84fd9SJoe Perches #define rdev_info(rdev, fmt, ...) \ 465da84fd9SJoe Perches pr_info("%s: " fmt, rdev_get_name(rdev), ##__VA_ARGS__) 475da84fd9SJoe Perches #define rdev_dbg(rdev, fmt, ...) \ 485da84fd9SJoe Perches pr_debug("%s: " fmt, rdev_get_name(rdev), ##__VA_ARGS__) 495da84fd9SJoe Perches 50414c70cbSLiam Girdwood static DEFINE_MUTEX(regulator_list_mutex); 51414c70cbSLiam Girdwood static LIST_HEAD(regulator_list); 52414c70cbSLiam Girdwood static LIST_HEAD(regulator_map_list); 5321cf891aSMark Brown static bool has_full_constraints; 54688fe99aSMark Brown static bool board_wants_dummy_regulator; 55414c70cbSLiam Girdwood 561130e5b3SMark Brown static struct dentry *debugfs_root; 571130e5b3SMark Brown 588dc5390dSMark Brown /* 59414c70cbSLiam Girdwood * struct regulator_map 60414c70cbSLiam Girdwood * 61414c70cbSLiam Girdwood * Used to provide symbolic supply names to devices. 62414c70cbSLiam Girdwood */ 63414c70cbSLiam Girdwood struct regulator_map { 64414c70cbSLiam Girdwood struct list_head list; 6540f9244fSMark Brown const char *dev_name; /* The dev_name() for the consumer */ 66414c70cbSLiam Girdwood const char *supply; 67a5766f11SLiam Girdwood struct regulator_dev *regulator; 68414c70cbSLiam Girdwood }; 69414c70cbSLiam Girdwood 70414c70cbSLiam Girdwood /* 71414c70cbSLiam Girdwood * struct regulator 72414c70cbSLiam Girdwood * 73414c70cbSLiam Girdwood * One for each consumer device. 74414c70cbSLiam Girdwood */ 75414c70cbSLiam Girdwood struct regulator { 76414c70cbSLiam Girdwood struct device *dev; 77414c70cbSLiam Girdwood struct list_head list; 78414c70cbSLiam Girdwood int uA_load; 79414c70cbSLiam Girdwood int min_uV; 80414c70cbSLiam Girdwood int max_uV; 81414c70cbSLiam Girdwood char *supply_name; 82414c70cbSLiam Girdwood struct device_attribute dev_attr; 83414c70cbSLiam Girdwood struct regulator_dev *rdev; 845de70519SMark Brown struct dentry *debugfs; 85414c70cbSLiam Girdwood }; 86414c70cbSLiam Girdwood 87414c70cbSLiam Girdwood static int _regulator_is_enabled(struct regulator_dev *rdev); 883801b86aSMark Brown static int _regulator_disable(struct regulator_dev *rdev); 89414c70cbSLiam Girdwood static int _regulator_get_voltage(struct regulator_dev *rdev); 90414c70cbSLiam Girdwood static int _regulator_get_current_limit(struct regulator_dev *rdev); 91414c70cbSLiam Girdwood static unsigned int _regulator_get_mode(struct regulator_dev *rdev); 92414c70cbSLiam Girdwood static void _notifier_call_chain(struct regulator_dev *rdev, 93414c70cbSLiam Girdwood unsigned long event, void *data); 9475790251SMark Brown static int _regulator_do_set_voltage(struct regulator_dev *rdev, 9575790251SMark Brown int min_uV, int max_uV); 963801b86aSMark Brown static struct regulator *create_regulator(struct regulator_dev *rdev, 973801b86aSMark Brown struct device *dev, 983801b86aSMark Brown const char *supply_name); 99414c70cbSLiam Girdwood 1001083c393SMark Brown static const char *rdev_get_name(struct regulator_dev *rdev) 1011083c393SMark Brown { 1021083c393SMark Brown if (rdev->constraints && rdev->constraints->name) 1031083c393SMark Brown return rdev->constraints->name; 1041083c393SMark Brown else if (rdev->desc->name) 1051083c393SMark Brown return rdev->desc->name; 1061083c393SMark Brown else 1071083c393SMark Brown return ""; 1081083c393SMark Brown } 1091083c393SMark Brown 110414c70cbSLiam Girdwood /* gets the regulator for a given consumer device */ 111414c70cbSLiam Girdwood static struct regulator *get_device_regulator(struct device *dev) 112414c70cbSLiam Girdwood { 113414c70cbSLiam Girdwood struct regulator *regulator = NULL; 114414c70cbSLiam Girdwood struct regulator_dev *rdev; 115414c70cbSLiam Girdwood 116414c70cbSLiam Girdwood mutex_lock(®ulator_list_mutex); 117414c70cbSLiam Girdwood list_for_each_entry(rdev, ®ulator_list, list) { 118414c70cbSLiam Girdwood mutex_lock(&rdev->mutex); 119414c70cbSLiam Girdwood list_for_each_entry(regulator, &rdev->consumer_list, list) { 120414c70cbSLiam Girdwood if (regulator->dev == dev) { 121414c70cbSLiam Girdwood mutex_unlock(&rdev->mutex); 122414c70cbSLiam Girdwood mutex_unlock(®ulator_list_mutex); 123414c70cbSLiam Girdwood return regulator; 124414c70cbSLiam Girdwood } 125414c70cbSLiam Girdwood } 126414c70cbSLiam Girdwood mutex_unlock(&rdev->mutex); 127414c70cbSLiam Girdwood } 128414c70cbSLiam Girdwood mutex_unlock(®ulator_list_mutex); 129414c70cbSLiam Girdwood return NULL; 130414c70cbSLiam Girdwood } 131414c70cbSLiam Girdwood 13269511a45SRajendra Nayak /** 13369511a45SRajendra Nayak * of_get_regulator - get a regulator device node based on supply name 13469511a45SRajendra Nayak * @dev: Device pointer for the consumer (of regulator) device 13569511a45SRajendra Nayak * @supply: regulator supply name 13669511a45SRajendra Nayak * 13769511a45SRajendra Nayak * Extract the regulator device node corresponding to the supply name. 13869511a45SRajendra Nayak * retruns the device node corresponding to the regulator if found, else 13969511a45SRajendra Nayak * returns NULL. 14069511a45SRajendra Nayak */ 14169511a45SRajendra Nayak static struct device_node *of_get_regulator(struct device *dev, const char *supply) 14269511a45SRajendra Nayak { 14369511a45SRajendra Nayak struct device_node *regnode = NULL; 14469511a45SRajendra Nayak char prop_name[32]; /* 32 is max size of property name */ 14569511a45SRajendra Nayak 14669511a45SRajendra Nayak dev_dbg(dev, "Looking up %s-supply from device tree\n", supply); 14769511a45SRajendra Nayak 14869511a45SRajendra Nayak snprintf(prop_name, 32, "%s-supply", supply); 14969511a45SRajendra Nayak regnode = of_parse_phandle(dev->of_node, prop_name, 0); 15069511a45SRajendra Nayak 15169511a45SRajendra Nayak if (!regnode) { 15216fbcc3bSRajendra Nayak dev_dbg(dev, "Looking up %s property in node %s failed", 15369511a45SRajendra Nayak prop_name, dev->of_node->full_name); 15469511a45SRajendra Nayak return NULL; 15569511a45SRajendra Nayak } 15669511a45SRajendra Nayak return regnode; 15769511a45SRajendra Nayak } 15869511a45SRajendra Nayak 159414c70cbSLiam Girdwood /* Platform voltage constraint check */ 160414c70cbSLiam Girdwood static int regulator_check_voltage(struct regulator_dev *rdev, 161414c70cbSLiam Girdwood int *min_uV, int *max_uV) 162414c70cbSLiam Girdwood { 163414c70cbSLiam Girdwood BUG_ON(*min_uV > *max_uV); 164414c70cbSLiam Girdwood 165414c70cbSLiam Girdwood if (!rdev->constraints) { 1665da84fd9SJoe Perches rdev_err(rdev, "no constraints\n"); 167414c70cbSLiam Girdwood return -ENODEV; 168414c70cbSLiam Girdwood } 169414c70cbSLiam Girdwood if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_VOLTAGE)) { 1705da84fd9SJoe Perches rdev_err(rdev, "operation not allowed\n"); 171414c70cbSLiam Girdwood return -EPERM; 172414c70cbSLiam Girdwood } 173414c70cbSLiam Girdwood 174414c70cbSLiam Girdwood if (*max_uV > rdev->constraints->max_uV) 175414c70cbSLiam Girdwood *max_uV = rdev->constraints->max_uV; 176414c70cbSLiam Girdwood if (*min_uV < rdev->constraints->min_uV) 177414c70cbSLiam Girdwood *min_uV = rdev->constraints->min_uV; 178414c70cbSLiam Girdwood 17989f425edSMark Brown if (*min_uV > *max_uV) { 18089f425edSMark Brown rdev_err(rdev, "unsupportable voltage range: %d-%duV\n", 18154abd335SMark Brown *min_uV, *max_uV); 182414c70cbSLiam Girdwood return -EINVAL; 18389f425edSMark Brown } 184414c70cbSLiam Girdwood 185414c70cbSLiam Girdwood return 0; 186414c70cbSLiam Girdwood } 187414c70cbSLiam Girdwood 18805fda3b1SThomas Petazzoni /* Make sure we select a voltage that suits the needs of all 18905fda3b1SThomas Petazzoni * regulator consumers 19005fda3b1SThomas Petazzoni */ 19105fda3b1SThomas Petazzoni static int regulator_check_consumers(struct regulator_dev *rdev, 19205fda3b1SThomas Petazzoni int *min_uV, int *max_uV) 19305fda3b1SThomas Petazzoni { 19405fda3b1SThomas Petazzoni struct regulator *regulator; 19505fda3b1SThomas Petazzoni 19605fda3b1SThomas Petazzoni list_for_each_entry(regulator, &rdev->consumer_list, list) { 1974aa922c0SMark Brown /* 1984aa922c0SMark Brown * Assume consumers that didn't say anything are OK 1994aa922c0SMark Brown * with anything in the constraint range. 2004aa922c0SMark Brown */ 2014aa922c0SMark Brown if (!regulator->min_uV && !regulator->max_uV) 2024aa922c0SMark Brown continue; 2034aa922c0SMark Brown 20405fda3b1SThomas Petazzoni if (*max_uV > regulator->max_uV) 20505fda3b1SThomas Petazzoni *max_uV = regulator->max_uV; 20605fda3b1SThomas Petazzoni if (*min_uV < regulator->min_uV) 20705fda3b1SThomas Petazzoni *min_uV = regulator->min_uV; 20805fda3b1SThomas Petazzoni } 20905fda3b1SThomas Petazzoni 21005fda3b1SThomas Petazzoni if (*min_uV > *max_uV) 21105fda3b1SThomas Petazzoni return -EINVAL; 21205fda3b1SThomas Petazzoni 21305fda3b1SThomas Petazzoni return 0; 21405fda3b1SThomas Petazzoni } 21505fda3b1SThomas Petazzoni 216414c70cbSLiam Girdwood /* current constraint check */ 217414c70cbSLiam Girdwood static int regulator_check_current_limit(struct regulator_dev *rdev, 218414c70cbSLiam Girdwood int *min_uA, int *max_uA) 219414c70cbSLiam Girdwood { 220414c70cbSLiam Girdwood BUG_ON(*min_uA > *max_uA); 221414c70cbSLiam Girdwood 222414c70cbSLiam Girdwood if (!rdev->constraints) { 2235da84fd9SJoe Perches rdev_err(rdev, "no constraints\n"); 224414c70cbSLiam Girdwood return -ENODEV; 225414c70cbSLiam Girdwood } 226414c70cbSLiam Girdwood if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_CURRENT)) { 2275da84fd9SJoe Perches rdev_err(rdev, "operation not allowed\n"); 228414c70cbSLiam Girdwood return -EPERM; 229414c70cbSLiam Girdwood } 230414c70cbSLiam Girdwood 231414c70cbSLiam Girdwood if (*max_uA > rdev->constraints->max_uA) 232414c70cbSLiam Girdwood *max_uA = rdev->constraints->max_uA; 233414c70cbSLiam Girdwood if (*min_uA < rdev->constraints->min_uA) 234414c70cbSLiam Girdwood *min_uA = rdev->constraints->min_uA; 235414c70cbSLiam Girdwood 23689f425edSMark Brown if (*min_uA > *max_uA) { 23789f425edSMark Brown rdev_err(rdev, "unsupportable current range: %d-%duA\n", 23854abd335SMark Brown *min_uA, *max_uA); 239414c70cbSLiam Girdwood return -EINVAL; 24089f425edSMark Brown } 241414c70cbSLiam Girdwood 242414c70cbSLiam Girdwood return 0; 243414c70cbSLiam Girdwood } 244414c70cbSLiam Girdwood 245414c70cbSLiam Girdwood /* operating mode constraint check */ 2462c608234SMark Brown static int regulator_mode_constrain(struct regulator_dev *rdev, int *mode) 247414c70cbSLiam Girdwood { 2482c608234SMark Brown switch (*mode) { 249e573520bSDavid Brownell case REGULATOR_MODE_FAST: 250e573520bSDavid Brownell case REGULATOR_MODE_NORMAL: 251e573520bSDavid Brownell case REGULATOR_MODE_IDLE: 252e573520bSDavid Brownell case REGULATOR_MODE_STANDBY: 253e573520bSDavid Brownell break; 254e573520bSDavid Brownell default: 25589f425edSMark Brown rdev_err(rdev, "invalid mode %x specified\n", *mode); 256e573520bSDavid Brownell return -EINVAL; 257e573520bSDavid Brownell } 258e573520bSDavid Brownell 259414c70cbSLiam Girdwood if (!rdev->constraints) { 2605da84fd9SJoe Perches rdev_err(rdev, "no constraints\n"); 261414c70cbSLiam Girdwood return -ENODEV; 262414c70cbSLiam Girdwood } 263414c70cbSLiam Girdwood if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_MODE)) { 2645da84fd9SJoe Perches rdev_err(rdev, "operation not allowed\n"); 265414c70cbSLiam Girdwood return -EPERM; 266414c70cbSLiam Girdwood } 2672c608234SMark Brown 2682c608234SMark Brown /* The modes are bitmasks, the most power hungry modes having 2692c608234SMark Brown * the lowest values. If the requested mode isn't supported 2702c608234SMark Brown * try higher modes. */ 2712c608234SMark Brown while (*mode) { 2722c608234SMark Brown if (rdev->constraints->valid_modes_mask & *mode) 273414c70cbSLiam Girdwood return 0; 2742c608234SMark Brown *mode /= 2; 2752c608234SMark Brown } 2762c608234SMark Brown 2772c608234SMark Brown return -EINVAL; 278414c70cbSLiam Girdwood } 279414c70cbSLiam Girdwood 280414c70cbSLiam Girdwood /* dynamic regulator mode switching constraint check */ 281414c70cbSLiam Girdwood static int regulator_check_drms(struct regulator_dev *rdev) 282414c70cbSLiam Girdwood { 283414c70cbSLiam Girdwood if (!rdev->constraints) { 2845da84fd9SJoe Perches rdev_err(rdev, "no constraints\n"); 285414c70cbSLiam Girdwood return -ENODEV; 286414c70cbSLiam Girdwood } 287414c70cbSLiam Girdwood if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_DRMS)) { 2885da84fd9SJoe Perches rdev_err(rdev, "operation not allowed\n"); 289414c70cbSLiam Girdwood return -EPERM; 290414c70cbSLiam Girdwood } 291414c70cbSLiam Girdwood return 0; 292414c70cbSLiam Girdwood } 293414c70cbSLiam Girdwood 294414c70cbSLiam Girdwood static ssize_t device_requested_uA_show(struct device *dev, 295414c70cbSLiam Girdwood struct device_attribute *attr, char *buf) 296414c70cbSLiam Girdwood { 297414c70cbSLiam Girdwood struct regulator *regulator; 298414c70cbSLiam Girdwood 299414c70cbSLiam Girdwood regulator = get_device_regulator(dev); 300414c70cbSLiam Girdwood if (regulator == NULL) 301414c70cbSLiam Girdwood return 0; 302414c70cbSLiam Girdwood 303414c70cbSLiam Girdwood return sprintf(buf, "%d\n", regulator->uA_load); 304414c70cbSLiam Girdwood } 305414c70cbSLiam Girdwood 306414c70cbSLiam Girdwood static ssize_t regulator_uV_show(struct device *dev, 307414c70cbSLiam Girdwood struct device_attribute *attr, char *buf) 308414c70cbSLiam Girdwood { 309a5766f11SLiam Girdwood struct regulator_dev *rdev = dev_get_drvdata(dev); 310414c70cbSLiam Girdwood ssize_t ret; 311414c70cbSLiam Girdwood 312414c70cbSLiam Girdwood mutex_lock(&rdev->mutex); 313414c70cbSLiam Girdwood ret = sprintf(buf, "%d\n", _regulator_get_voltage(rdev)); 314414c70cbSLiam Girdwood mutex_unlock(&rdev->mutex); 315414c70cbSLiam Girdwood 316414c70cbSLiam Girdwood return ret; 317414c70cbSLiam Girdwood } 3187ad68e2fSDavid Brownell static DEVICE_ATTR(microvolts, 0444, regulator_uV_show, NULL); 319414c70cbSLiam Girdwood 320414c70cbSLiam Girdwood static ssize_t regulator_uA_show(struct device *dev, 321414c70cbSLiam Girdwood struct device_attribute *attr, char *buf) 322414c70cbSLiam Girdwood { 323a5766f11SLiam Girdwood struct regulator_dev *rdev = dev_get_drvdata(dev); 324414c70cbSLiam Girdwood 325414c70cbSLiam Girdwood return sprintf(buf, "%d\n", _regulator_get_current_limit(rdev)); 326414c70cbSLiam Girdwood } 3277ad68e2fSDavid Brownell static DEVICE_ATTR(microamps, 0444, regulator_uA_show, NULL); 328414c70cbSLiam Girdwood 329bc558a60SMark Brown static ssize_t regulator_name_show(struct device *dev, 330bc558a60SMark Brown struct device_attribute *attr, char *buf) 331bc558a60SMark Brown { 332bc558a60SMark Brown struct regulator_dev *rdev = dev_get_drvdata(dev); 333bc558a60SMark Brown 3341083c393SMark Brown return sprintf(buf, "%s\n", rdev_get_name(rdev)); 335bc558a60SMark Brown } 336bc558a60SMark Brown 3374fca9545SDavid Brownell static ssize_t regulator_print_opmode(char *buf, int mode) 338414c70cbSLiam Girdwood { 339414c70cbSLiam Girdwood switch (mode) { 340414c70cbSLiam Girdwood case REGULATOR_MODE_FAST: 341414c70cbSLiam Girdwood return sprintf(buf, "fast\n"); 342414c70cbSLiam Girdwood case REGULATOR_MODE_NORMAL: 343414c70cbSLiam Girdwood return sprintf(buf, "normal\n"); 344414c70cbSLiam Girdwood case REGULATOR_MODE_IDLE: 345414c70cbSLiam Girdwood return sprintf(buf, "idle\n"); 346414c70cbSLiam Girdwood case REGULATOR_MODE_STANDBY: 347414c70cbSLiam Girdwood return sprintf(buf, "standby\n"); 348414c70cbSLiam Girdwood } 349414c70cbSLiam Girdwood return sprintf(buf, "unknown\n"); 350414c70cbSLiam Girdwood } 351414c70cbSLiam Girdwood 3524fca9545SDavid Brownell static ssize_t regulator_opmode_show(struct device *dev, 353414c70cbSLiam Girdwood struct device_attribute *attr, char *buf) 354414c70cbSLiam Girdwood { 355a5766f11SLiam Girdwood struct regulator_dev *rdev = dev_get_drvdata(dev); 356414c70cbSLiam Girdwood 3574fca9545SDavid Brownell return regulator_print_opmode(buf, _regulator_get_mode(rdev)); 3584fca9545SDavid Brownell } 3597ad68e2fSDavid Brownell static DEVICE_ATTR(opmode, 0444, regulator_opmode_show, NULL); 3604fca9545SDavid Brownell 3614fca9545SDavid Brownell static ssize_t regulator_print_state(char *buf, int state) 3624fca9545SDavid Brownell { 363414c70cbSLiam Girdwood if (state > 0) 364414c70cbSLiam Girdwood return sprintf(buf, "enabled\n"); 365414c70cbSLiam Girdwood else if (state == 0) 366414c70cbSLiam Girdwood return sprintf(buf, "disabled\n"); 367414c70cbSLiam Girdwood else 368414c70cbSLiam Girdwood return sprintf(buf, "unknown\n"); 369414c70cbSLiam Girdwood } 370414c70cbSLiam Girdwood 3714fca9545SDavid Brownell static ssize_t regulator_state_show(struct device *dev, 3724fca9545SDavid Brownell struct device_attribute *attr, char *buf) 3734fca9545SDavid Brownell { 3744fca9545SDavid Brownell struct regulator_dev *rdev = dev_get_drvdata(dev); 3759332546fSMark Brown ssize_t ret; 3764fca9545SDavid Brownell 3779332546fSMark Brown mutex_lock(&rdev->mutex); 3789332546fSMark Brown ret = regulator_print_state(buf, _regulator_is_enabled(rdev)); 3799332546fSMark Brown mutex_unlock(&rdev->mutex); 3809332546fSMark Brown 3819332546fSMark Brown return ret; 3824fca9545SDavid Brownell } 3837ad68e2fSDavid Brownell static DEVICE_ATTR(state, 0444, regulator_state_show, NULL); 3844fca9545SDavid Brownell 385853116a1SDavid Brownell static ssize_t regulator_status_show(struct device *dev, 386853116a1SDavid Brownell struct device_attribute *attr, char *buf) 387853116a1SDavid Brownell { 388853116a1SDavid Brownell struct regulator_dev *rdev = dev_get_drvdata(dev); 389853116a1SDavid Brownell int status; 390853116a1SDavid Brownell char *label; 391853116a1SDavid Brownell 392853116a1SDavid Brownell status = rdev->desc->ops->get_status(rdev); 393853116a1SDavid Brownell if (status < 0) 394853116a1SDavid Brownell return status; 395853116a1SDavid Brownell 396853116a1SDavid Brownell switch (status) { 397853116a1SDavid Brownell case REGULATOR_STATUS_OFF: 398853116a1SDavid Brownell label = "off"; 399853116a1SDavid Brownell break; 400853116a1SDavid Brownell case REGULATOR_STATUS_ON: 401853116a1SDavid Brownell label = "on"; 402853116a1SDavid Brownell break; 403853116a1SDavid Brownell case REGULATOR_STATUS_ERROR: 404853116a1SDavid Brownell label = "error"; 405853116a1SDavid Brownell break; 406853116a1SDavid Brownell case REGULATOR_STATUS_FAST: 407853116a1SDavid Brownell label = "fast"; 408853116a1SDavid Brownell break; 409853116a1SDavid Brownell case REGULATOR_STATUS_NORMAL: 410853116a1SDavid Brownell label = "normal"; 411853116a1SDavid Brownell break; 412853116a1SDavid Brownell case REGULATOR_STATUS_IDLE: 413853116a1SDavid Brownell label = "idle"; 414853116a1SDavid Brownell break; 415853116a1SDavid Brownell case REGULATOR_STATUS_STANDBY: 416853116a1SDavid Brownell label = "standby"; 417853116a1SDavid Brownell break; 418853116a1SDavid Brownell default: 419853116a1SDavid Brownell return -ERANGE; 420853116a1SDavid Brownell } 421853116a1SDavid Brownell 422853116a1SDavid Brownell return sprintf(buf, "%s\n", label); 423853116a1SDavid Brownell } 424853116a1SDavid Brownell static DEVICE_ATTR(status, 0444, regulator_status_show, NULL); 425853116a1SDavid Brownell 426414c70cbSLiam Girdwood static ssize_t regulator_min_uA_show(struct device *dev, 427414c70cbSLiam Girdwood struct device_attribute *attr, char *buf) 428414c70cbSLiam Girdwood { 429a5766f11SLiam Girdwood struct regulator_dev *rdev = dev_get_drvdata(dev); 430414c70cbSLiam Girdwood 431414c70cbSLiam Girdwood if (!rdev->constraints) 432414c70cbSLiam Girdwood return sprintf(buf, "constraint not defined\n"); 433414c70cbSLiam Girdwood 434414c70cbSLiam Girdwood return sprintf(buf, "%d\n", rdev->constraints->min_uA); 435414c70cbSLiam Girdwood } 4367ad68e2fSDavid Brownell static DEVICE_ATTR(min_microamps, 0444, regulator_min_uA_show, NULL); 437414c70cbSLiam Girdwood 438414c70cbSLiam Girdwood static ssize_t regulator_max_uA_show(struct device *dev, 439414c70cbSLiam Girdwood struct device_attribute *attr, char *buf) 440414c70cbSLiam Girdwood { 441a5766f11SLiam Girdwood struct regulator_dev *rdev = dev_get_drvdata(dev); 442414c70cbSLiam Girdwood 443414c70cbSLiam Girdwood if (!rdev->constraints) 444414c70cbSLiam Girdwood return sprintf(buf, "constraint not defined\n"); 445414c70cbSLiam Girdwood 446414c70cbSLiam Girdwood return sprintf(buf, "%d\n", rdev->constraints->max_uA); 447414c70cbSLiam Girdwood } 4487ad68e2fSDavid Brownell static DEVICE_ATTR(max_microamps, 0444, regulator_max_uA_show, NULL); 449414c70cbSLiam Girdwood 450414c70cbSLiam Girdwood static ssize_t regulator_min_uV_show(struct device *dev, 451414c70cbSLiam Girdwood struct device_attribute *attr, char *buf) 452414c70cbSLiam Girdwood { 453a5766f11SLiam Girdwood struct regulator_dev *rdev = dev_get_drvdata(dev); 454414c70cbSLiam Girdwood 455414c70cbSLiam Girdwood if (!rdev->constraints) 456414c70cbSLiam Girdwood return sprintf(buf, "constraint not defined\n"); 457414c70cbSLiam Girdwood 458414c70cbSLiam Girdwood return sprintf(buf, "%d\n", rdev->constraints->min_uV); 459414c70cbSLiam Girdwood } 4607ad68e2fSDavid Brownell static DEVICE_ATTR(min_microvolts, 0444, regulator_min_uV_show, NULL); 461414c70cbSLiam Girdwood 462414c70cbSLiam Girdwood static ssize_t regulator_max_uV_show(struct device *dev, 463414c70cbSLiam Girdwood struct device_attribute *attr, char *buf) 464414c70cbSLiam Girdwood { 465a5766f11SLiam Girdwood struct regulator_dev *rdev = dev_get_drvdata(dev); 466414c70cbSLiam Girdwood 467414c70cbSLiam Girdwood if (!rdev->constraints) 468414c70cbSLiam Girdwood return sprintf(buf, "constraint not defined\n"); 469414c70cbSLiam Girdwood 470414c70cbSLiam Girdwood return sprintf(buf, "%d\n", rdev->constraints->max_uV); 471414c70cbSLiam Girdwood } 4727ad68e2fSDavid Brownell static DEVICE_ATTR(max_microvolts, 0444, regulator_max_uV_show, NULL); 473414c70cbSLiam Girdwood 474414c70cbSLiam Girdwood static ssize_t regulator_total_uA_show(struct device *dev, 475414c70cbSLiam Girdwood struct device_attribute *attr, char *buf) 476414c70cbSLiam Girdwood { 477a5766f11SLiam Girdwood struct regulator_dev *rdev = dev_get_drvdata(dev); 478414c70cbSLiam Girdwood struct regulator *regulator; 479414c70cbSLiam Girdwood int uA = 0; 480414c70cbSLiam Girdwood 481414c70cbSLiam Girdwood mutex_lock(&rdev->mutex); 482414c70cbSLiam Girdwood list_for_each_entry(regulator, &rdev->consumer_list, list) 483414c70cbSLiam Girdwood uA += regulator->uA_load; 484414c70cbSLiam Girdwood mutex_unlock(&rdev->mutex); 485414c70cbSLiam Girdwood return sprintf(buf, "%d\n", uA); 486414c70cbSLiam Girdwood } 4877ad68e2fSDavid Brownell static DEVICE_ATTR(requested_microamps, 0444, regulator_total_uA_show, NULL); 488414c70cbSLiam Girdwood 489414c70cbSLiam Girdwood static ssize_t regulator_num_users_show(struct device *dev, 490414c70cbSLiam Girdwood struct device_attribute *attr, char *buf) 491414c70cbSLiam Girdwood { 492a5766f11SLiam Girdwood struct regulator_dev *rdev = dev_get_drvdata(dev); 493414c70cbSLiam Girdwood return sprintf(buf, "%d\n", rdev->use_count); 494414c70cbSLiam Girdwood } 495414c70cbSLiam Girdwood 496414c70cbSLiam Girdwood static ssize_t regulator_type_show(struct device *dev, 497414c70cbSLiam Girdwood struct device_attribute *attr, char *buf) 498414c70cbSLiam Girdwood { 499a5766f11SLiam Girdwood struct regulator_dev *rdev = dev_get_drvdata(dev); 500414c70cbSLiam Girdwood 501414c70cbSLiam Girdwood switch (rdev->desc->type) { 502414c70cbSLiam Girdwood case REGULATOR_VOLTAGE: 503414c70cbSLiam Girdwood return sprintf(buf, "voltage\n"); 504414c70cbSLiam Girdwood case REGULATOR_CURRENT: 505414c70cbSLiam Girdwood return sprintf(buf, "current\n"); 506414c70cbSLiam Girdwood } 507414c70cbSLiam Girdwood return sprintf(buf, "unknown\n"); 508414c70cbSLiam Girdwood } 509414c70cbSLiam Girdwood 510414c70cbSLiam Girdwood static ssize_t regulator_suspend_mem_uV_show(struct device *dev, 511414c70cbSLiam Girdwood struct device_attribute *attr, char *buf) 512414c70cbSLiam Girdwood { 513a5766f11SLiam Girdwood struct regulator_dev *rdev = dev_get_drvdata(dev); 514414c70cbSLiam Girdwood 515414c70cbSLiam Girdwood return sprintf(buf, "%d\n", rdev->constraints->state_mem.uV); 516414c70cbSLiam Girdwood } 5177ad68e2fSDavid Brownell static DEVICE_ATTR(suspend_mem_microvolts, 0444, 5187ad68e2fSDavid Brownell regulator_suspend_mem_uV_show, NULL); 519414c70cbSLiam Girdwood 520414c70cbSLiam Girdwood static ssize_t regulator_suspend_disk_uV_show(struct device *dev, 521414c70cbSLiam Girdwood struct device_attribute *attr, char *buf) 522414c70cbSLiam Girdwood { 523a5766f11SLiam Girdwood struct regulator_dev *rdev = dev_get_drvdata(dev); 524414c70cbSLiam Girdwood 525414c70cbSLiam Girdwood return sprintf(buf, "%d\n", rdev->constraints->state_disk.uV); 526414c70cbSLiam Girdwood } 5277ad68e2fSDavid Brownell static DEVICE_ATTR(suspend_disk_microvolts, 0444, 5287ad68e2fSDavid Brownell regulator_suspend_disk_uV_show, NULL); 529414c70cbSLiam Girdwood 530414c70cbSLiam Girdwood static ssize_t regulator_suspend_standby_uV_show(struct device *dev, 531414c70cbSLiam Girdwood struct device_attribute *attr, char *buf) 532414c70cbSLiam Girdwood { 533a5766f11SLiam Girdwood struct regulator_dev *rdev = dev_get_drvdata(dev); 534414c70cbSLiam Girdwood 535414c70cbSLiam Girdwood return sprintf(buf, "%d\n", rdev->constraints->state_standby.uV); 536414c70cbSLiam Girdwood } 5377ad68e2fSDavid Brownell static DEVICE_ATTR(suspend_standby_microvolts, 0444, 5387ad68e2fSDavid Brownell regulator_suspend_standby_uV_show, NULL); 539414c70cbSLiam Girdwood 540414c70cbSLiam Girdwood static ssize_t regulator_suspend_mem_mode_show(struct device *dev, 541414c70cbSLiam Girdwood struct device_attribute *attr, char *buf) 542414c70cbSLiam Girdwood { 543a5766f11SLiam Girdwood struct regulator_dev *rdev = dev_get_drvdata(dev); 544414c70cbSLiam Girdwood 5454fca9545SDavid Brownell return regulator_print_opmode(buf, 5464fca9545SDavid Brownell rdev->constraints->state_mem.mode); 547414c70cbSLiam Girdwood } 5487ad68e2fSDavid Brownell static DEVICE_ATTR(suspend_mem_mode, 0444, 5497ad68e2fSDavid Brownell regulator_suspend_mem_mode_show, NULL); 550414c70cbSLiam Girdwood 551414c70cbSLiam Girdwood static ssize_t regulator_suspend_disk_mode_show(struct device *dev, 552414c70cbSLiam Girdwood struct device_attribute *attr, char *buf) 553414c70cbSLiam Girdwood { 554a5766f11SLiam Girdwood struct regulator_dev *rdev = dev_get_drvdata(dev); 555414c70cbSLiam Girdwood 5564fca9545SDavid Brownell return regulator_print_opmode(buf, 5574fca9545SDavid Brownell rdev->constraints->state_disk.mode); 558414c70cbSLiam Girdwood } 5597ad68e2fSDavid Brownell static DEVICE_ATTR(suspend_disk_mode, 0444, 5607ad68e2fSDavid Brownell regulator_suspend_disk_mode_show, NULL); 561414c70cbSLiam Girdwood 562414c70cbSLiam Girdwood static ssize_t regulator_suspend_standby_mode_show(struct device *dev, 563414c70cbSLiam Girdwood struct device_attribute *attr, char *buf) 564414c70cbSLiam Girdwood { 565a5766f11SLiam Girdwood struct regulator_dev *rdev = dev_get_drvdata(dev); 566414c70cbSLiam Girdwood 5674fca9545SDavid Brownell return regulator_print_opmode(buf, 5684fca9545SDavid Brownell rdev->constraints->state_standby.mode); 569414c70cbSLiam Girdwood } 5707ad68e2fSDavid Brownell static DEVICE_ATTR(suspend_standby_mode, 0444, 5717ad68e2fSDavid Brownell regulator_suspend_standby_mode_show, NULL); 572414c70cbSLiam Girdwood 573414c70cbSLiam Girdwood static ssize_t regulator_suspend_mem_state_show(struct device *dev, 574414c70cbSLiam Girdwood struct device_attribute *attr, char *buf) 575414c70cbSLiam Girdwood { 576a5766f11SLiam Girdwood struct regulator_dev *rdev = dev_get_drvdata(dev); 577414c70cbSLiam Girdwood 5784fca9545SDavid Brownell return regulator_print_state(buf, 5794fca9545SDavid Brownell rdev->constraints->state_mem.enabled); 580414c70cbSLiam Girdwood } 5817ad68e2fSDavid Brownell static DEVICE_ATTR(suspend_mem_state, 0444, 5827ad68e2fSDavid Brownell regulator_suspend_mem_state_show, NULL); 583414c70cbSLiam Girdwood 584414c70cbSLiam Girdwood static ssize_t regulator_suspend_disk_state_show(struct device *dev, 585414c70cbSLiam Girdwood struct device_attribute *attr, char *buf) 586414c70cbSLiam Girdwood { 587a5766f11SLiam Girdwood struct regulator_dev *rdev = dev_get_drvdata(dev); 588414c70cbSLiam Girdwood 5894fca9545SDavid Brownell return regulator_print_state(buf, 5904fca9545SDavid Brownell rdev->constraints->state_disk.enabled); 591414c70cbSLiam Girdwood } 5927ad68e2fSDavid Brownell static DEVICE_ATTR(suspend_disk_state, 0444, 5937ad68e2fSDavid Brownell regulator_suspend_disk_state_show, NULL); 594414c70cbSLiam Girdwood 595414c70cbSLiam Girdwood static ssize_t regulator_suspend_standby_state_show(struct device *dev, 596414c70cbSLiam Girdwood struct device_attribute *attr, char *buf) 597414c70cbSLiam Girdwood { 598a5766f11SLiam Girdwood struct regulator_dev *rdev = dev_get_drvdata(dev); 599414c70cbSLiam Girdwood 6004fca9545SDavid Brownell return regulator_print_state(buf, 6014fca9545SDavid Brownell rdev->constraints->state_standby.enabled); 602414c70cbSLiam Girdwood } 6037ad68e2fSDavid Brownell static DEVICE_ATTR(suspend_standby_state, 0444, 6047ad68e2fSDavid Brownell regulator_suspend_standby_state_show, NULL); 605bc558a60SMark Brown 6067ad68e2fSDavid Brownell 6077ad68e2fSDavid Brownell /* 6087ad68e2fSDavid Brownell * These are the only attributes are present for all regulators. 6097ad68e2fSDavid Brownell * Other attributes are a function of regulator functionality. 6107ad68e2fSDavid Brownell */ 611414c70cbSLiam Girdwood static struct device_attribute regulator_dev_attrs[] = { 612bc558a60SMark Brown __ATTR(name, 0444, regulator_name_show, NULL), 613414c70cbSLiam Girdwood __ATTR(num_users, 0444, regulator_num_users_show, NULL), 614414c70cbSLiam Girdwood __ATTR(type, 0444, regulator_type_show, NULL), 615414c70cbSLiam Girdwood __ATTR_NULL, 616414c70cbSLiam Girdwood }; 617414c70cbSLiam Girdwood 618414c70cbSLiam Girdwood static void regulator_dev_release(struct device *dev) 619414c70cbSLiam Girdwood { 620a5766f11SLiam Girdwood struct regulator_dev *rdev = dev_get_drvdata(dev); 621414c70cbSLiam Girdwood kfree(rdev); 622414c70cbSLiam Girdwood } 623414c70cbSLiam Girdwood 624414c70cbSLiam Girdwood static struct class regulator_class = { 625414c70cbSLiam Girdwood .name = "regulator", 626414c70cbSLiam Girdwood .dev_release = regulator_dev_release, 627414c70cbSLiam Girdwood .dev_attrs = regulator_dev_attrs, 628414c70cbSLiam Girdwood }; 629414c70cbSLiam Girdwood 630414c70cbSLiam Girdwood /* Calculate the new optimum regulator operating mode based on the new total 631414c70cbSLiam Girdwood * consumer load. All locks held by caller */ 632414c70cbSLiam Girdwood static void drms_uA_update(struct regulator_dev *rdev) 633414c70cbSLiam Girdwood { 634414c70cbSLiam Girdwood struct regulator *sibling; 635414c70cbSLiam Girdwood int current_uA = 0, output_uV, input_uV, err; 636414c70cbSLiam Girdwood unsigned int mode; 637414c70cbSLiam Girdwood 638414c70cbSLiam Girdwood err = regulator_check_drms(rdev); 639414c70cbSLiam Girdwood if (err < 0 || !rdev->desc->ops->get_optimum_mode || 640476c2d83SMark Brown (!rdev->desc->ops->get_voltage && 641476c2d83SMark Brown !rdev->desc->ops->get_voltage_sel) || 642476c2d83SMark Brown !rdev->desc->ops->set_mode) 643414c70cbSLiam Girdwood return; 644414c70cbSLiam Girdwood 645414c70cbSLiam Girdwood /* get output voltage */ 6461bf5a1f8SMark Brown output_uV = _regulator_get_voltage(rdev); 647414c70cbSLiam Girdwood if (output_uV <= 0) 648414c70cbSLiam Girdwood return; 649414c70cbSLiam Girdwood 650414c70cbSLiam Girdwood /* get input voltage */ 6511bf5a1f8SMark Brown input_uV = 0; 6521bf5a1f8SMark Brown if (rdev->supply) 6531bf5a1f8SMark Brown input_uV = _regulator_get_voltage(rdev); 6541bf5a1f8SMark Brown if (input_uV <= 0) 655414c70cbSLiam Girdwood input_uV = rdev->constraints->input_uV; 656414c70cbSLiam Girdwood if (input_uV <= 0) 657414c70cbSLiam Girdwood return; 658414c70cbSLiam Girdwood 659414c70cbSLiam Girdwood /* calc total requested load */ 660414c70cbSLiam Girdwood list_for_each_entry(sibling, &rdev->consumer_list, list) 661414c70cbSLiam Girdwood current_uA += sibling->uA_load; 662414c70cbSLiam Girdwood 663414c70cbSLiam Girdwood /* now get the optimum mode for our new total regulator load */ 664414c70cbSLiam Girdwood mode = rdev->desc->ops->get_optimum_mode(rdev, input_uV, 665414c70cbSLiam Girdwood output_uV, current_uA); 666414c70cbSLiam Girdwood 667414c70cbSLiam Girdwood /* check the new mode is allowed */ 6682c608234SMark Brown err = regulator_mode_constrain(rdev, &mode); 669414c70cbSLiam Girdwood if (err == 0) 670414c70cbSLiam Girdwood rdev->desc->ops->set_mode(rdev, mode); 671414c70cbSLiam Girdwood } 672414c70cbSLiam Girdwood 673414c70cbSLiam Girdwood static int suspend_set_state(struct regulator_dev *rdev, 674414c70cbSLiam Girdwood struct regulator_state *rstate) 675414c70cbSLiam Girdwood { 676414c70cbSLiam Girdwood int ret = 0; 677638f85c5SMark Brown bool can_set_state; 678414c70cbSLiam Girdwood 679638f85c5SMark Brown can_set_state = rdev->desc->ops->set_suspend_enable && 680638f85c5SMark Brown rdev->desc->ops->set_suspend_disable; 681638f85c5SMark Brown 682638f85c5SMark Brown /* If we have no suspend mode configration don't set anything; 683638f85c5SMark Brown * only warn if the driver actually makes the suspend mode 684638f85c5SMark Brown * configurable. 685638f85c5SMark Brown */ 686638f85c5SMark Brown if (!rstate->enabled && !rstate->disabled) { 687638f85c5SMark Brown if (can_set_state) 6885da84fd9SJoe Perches rdev_warn(rdev, "No configuration\n"); 689638f85c5SMark Brown return 0; 690638f85c5SMark Brown } 691638f85c5SMark Brown 692638f85c5SMark Brown if (rstate->enabled && rstate->disabled) { 6935da84fd9SJoe Perches rdev_err(rdev, "invalid configuration\n"); 694638f85c5SMark Brown return -EINVAL; 695638f85c5SMark Brown } 696638f85c5SMark Brown 697638f85c5SMark Brown if (!can_set_state) { 6985da84fd9SJoe Perches rdev_err(rdev, "no way to set suspend state\n"); 699414c70cbSLiam Girdwood return -EINVAL; 700a5766f11SLiam Girdwood } 701414c70cbSLiam Girdwood 702414c70cbSLiam Girdwood if (rstate->enabled) 703414c70cbSLiam Girdwood ret = rdev->desc->ops->set_suspend_enable(rdev); 704414c70cbSLiam Girdwood else 705414c70cbSLiam Girdwood ret = rdev->desc->ops->set_suspend_disable(rdev); 706414c70cbSLiam Girdwood if (ret < 0) { 7075da84fd9SJoe Perches rdev_err(rdev, "failed to enabled/disable\n"); 708414c70cbSLiam Girdwood return ret; 709414c70cbSLiam Girdwood } 710414c70cbSLiam Girdwood 711414c70cbSLiam Girdwood if (rdev->desc->ops->set_suspend_voltage && rstate->uV > 0) { 712414c70cbSLiam Girdwood ret = rdev->desc->ops->set_suspend_voltage(rdev, rstate->uV); 713414c70cbSLiam Girdwood if (ret < 0) { 7145da84fd9SJoe Perches rdev_err(rdev, "failed to set voltage\n"); 715414c70cbSLiam Girdwood return ret; 716414c70cbSLiam Girdwood } 717414c70cbSLiam Girdwood } 718414c70cbSLiam Girdwood 719414c70cbSLiam Girdwood if (rdev->desc->ops->set_suspend_mode && rstate->mode > 0) { 720414c70cbSLiam Girdwood ret = rdev->desc->ops->set_suspend_mode(rdev, rstate->mode); 721414c70cbSLiam Girdwood if (ret < 0) { 7225da84fd9SJoe Perches rdev_err(rdev, "failed to set mode\n"); 723414c70cbSLiam Girdwood return ret; 724414c70cbSLiam Girdwood } 725414c70cbSLiam Girdwood } 726414c70cbSLiam Girdwood return ret; 727414c70cbSLiam Girdwood } 728414c70cbSLiam Girdwood 729414c70cbSLiam Girdwood /* locks held by caller */ 730414c70cbSLiam Girdwood static int suspend_prepare(struct regulator_dev *rdev, suspend_state_t state) 731414c70cbSLiam Girdwood { 732414c70cbSLiam Girdwood if (!rdev->constraints) 733414c70cbSLiam Girdwood return -EINVAL; 734414c70cbSLiam Girdwood 735414c70cbSLiam Girdwood switch (state) { 736414c70cbSLiam Girdwood case PM_SUSPEND_STANDBY: 737414c70cbSLiam Girdwood return suspend_set_state(rdev, 738414c70cbSLiam Girdwood &rdev->constraints->state_standby); 739414c70cbSLiam Girdwood case PM_SUSPEND_MEM: 740414c70cbSLiam Girdwood return suspend_set_state(rdev, 741414c70cbSLiam Girdwood &rdev->constraints->state_mem); 742414c70cbSLiam Girdwood case PM_SUSPEND_MAX: 743414c70cbSLiam Girdwood return suspend_set_state(rdev, 744414c70cbSLiam Girdwood &rdev->constraints->state_disk); 745414c70cbSLiam Girdwood default: 746414c70cbSLiam Girdwood return -EINVAL; 747414c70cbSLiam Girdwood } 748414c70cbSLiam Girdwood } 749414c70cbSLiam Girdwood 750414c70cbSLiam Girdwood static void print_constraints(struct regulator_dev *rdev) 751414c70cbSLiam Girdwood { 752414c70cbSLiam Girdwood struct regulation_constraints *constraints = rdev->constraints; 753973e9a27SMark Brown char buf[80] = ""; 7548f031b48SMark Brown int count = 0; 7558f031b48SMark Brown int ret; 756414c70cbSLiam Girdwood 7578f031b48SMark Brown if (constraints->min_uV && constraints->max_uV) { 758414c70cbSLiam Girdwood if (constraints->min_uV == constraints->max_uV) 7598f031b48SMark Brown count += sprintf(buf + count, "%d mV ", 760414c70cbSLiam Girdwood constraints->min_uV / 1000); 761414c70cbSLiam Girdwood else 7628f031b48SMark Brown count += sprintf(buf + count, "%d <--> %d mV ", 763414c70cbSLiam Girdwood constraints->min_uV / 1000, 764414c70cbSLiam Girdwood constraints->max_uV / 1000); 7658f031b48SMark Brown } 7668f031b48SMark Brown 7678f031b48SMark Brown if (!constraints->min_uV || 7688f031b48SMark Brown constraints->min_uV != constraints->max_uV) { 7698f031b48SMark Brown ret = _regulator_get_voltage(rdev); 7708f031b48SMark Brown if (ret > 0) 7718f031b48SMark Brown count += sprintf(buf + count, "at %d mV ", ret / 1000); 7728f031b48SMark Brown } 7738f031b48SMark Brown 774bf5892a8SMark Brown if (constraints->uV_offset) 775bf5892a8SMark Brown count += sprintf(buf, "%dmV offset ", 776bf5892a8SMark Brown constraints->uV_offset / 1000); 777bf5892a8SMark Brown 7788f031b48SMark Brown if (constraints->min_uA && constraints->max_uA) { 779414c70cbSLiam Girdwood if (constraints->min_uA == constraints->max_uA) 7808f031b48SMark Brown count += sprintf(buf + count, "%d mA ", 781414c70cbSLiam Girdwood constraints->min_uA / 1000); 782414c70cbSLiam Girdwood else 7838f031b48SMark Brown count += sprintf(buf + count, "%d <--> %d mA ", 784414c70cbSLiam Girdwood constraints->min_uA / 1000, 785414c70cbSLiam Girdwood constraints->max_uA / 1000); 786414c70cbSLiam Girdwood } 7878f031b48SMark Brown 7888f031b48SMark Brown if (!constraints->min_uA || 7898f031b48SMark Brown constraints->min_uA != constraints->max_uA) { 7908f031b48SMark Brown ret = _regulator_get_current_limit(rdev); 7918f031b48SMark Brown if (ret > 0) 792e4a6376bSCyril Chemparathy count += sprintf(buf + count, "at %d mA ", ret / 1000); 7938f031b48SMark Brown } 7948f031b48SMark Brown 795414c70cbSLiam Girdwood if (constraints->valid_modes_mask & REGULATOR_MODE_FAST) 796414c70cbSLiam Girdwood count += sprintf(buf + count, "fast "); 797414c70cbSLiam Girdwood if (constraints->valid_modes_mask & REGULATOR_MODE_NORMAL) 798414c70cbSLiam Girdwood count += sprintf(buf + count, "normal "); 799414c70cbSLiam Girdwood if (constraints->valid_modes_mask & REGULATOR_MODE_IDLE) 800414c70cbSLiam Girdwood count += sprintf(buf + count, "idle "); 801414c70cbSLiam Girdwood if (constraints->valid_modes_mask & REGULATOR_MODE_STANDBY) 802414c70cbSLiam Girdwood count += sprintf(buf + count, "standby"); 803414c70cbSLiam Girdwood 80413ce29f8SMark Brown rdev_info(rdev, "%s\n", buf); 8054a682922SMark Brown 8064a682922SMark Brown if ((constraints->min_uV != constraints->max_uV) && 8074a682922SMark Brown !(constraints->valid_ops_mask & REGULATOR_CHANGE_VOLTAGE)) 8084a682922SMark Brown rdev_warn(rdev, 8094a682922SMark Brown "Voltage range but no REGULATOR_CHANGE_VOLTAGE\n"); 810414c70cbSLiam Girdwood } 811414c70cbSLiam Girdwood 812e79055d6SMark Brown static int machine_constraints_voltage(struct regulator_dev *rdev, 8131083c393SMark Brown struct regulation_constraints *constraints) 814e79055d6SMark Brown { 815e79055d6SMark Brown struct regulator_ops *ops = rdev->desc->ops; 816af5866c9SMark Brown int ret; 817af5866c9SMark Brown 818af5866c9SMark Brown /* do we need to apply the constraint voltage */ 819af5866c9SMark Brown if (rdev->constraints->apply_uV && 82075790251SMark Brown rdev->constraints->min_uV == rdev->constraints->max_uV) { 82175790251SMark Brown ret = _regulator_do_set_voltage(rdev, 8223a93f2a9SMark Brown rdev->constraints->min_uV, 82375790251SMark Brown rdev->constraints->max_uV); 824af5866c9SMark Brown if (ret < 0) { 8255da84fd9SJoe Perches rdev_err(rdev, "failed to apply %duV constraint\n", 8265da84fd9SJoe Perches rdev->constraints->min_uV); 827af5866c9SMark Brown return ret; 828af5866c9SMark Brown } 829af5866c9SMark Brown } 830e79055d6SMark Brown 831e79055d6SMark Brown /* constrain machine-level voltage specs to fit 832e79055d6SMark Brown * the actual range supported by this regulator. 833e79055d6SMark Brown */ 834e79055d6SMark Brown if (ops->list_voltage && rdev->desc->n_voltages) { 835e79055d6SMark Brown int count = rdev->desc->n_voltages; 836e79055d6SMark Brown int i; 837e79055d6SMark Brown int min_uV = INT_MAX; 838e79055d6SMark Brown int max_uV = INT_MIN; 839e79055d6SMark Brown int cmin = constraints->min_uV; 840e79055d6SMark Brown int cmax = constraints->max_uV; 841e79055d6SMark Brown 842e79055d6SMark Brown /* it's safe to autoconfigure fixed-voltage supplies 843e79055d6SMark Brown and the constraints are used by list_voltage. */ 844e79055d6SMark Brown if (count == 1 && !cmin) { 845e79055d6SMark Brown cmin = 1; 846e79055d6SMark Brown cmax = INT_MAX; 847e79055d6SMark Brown constraints->min_uV = cmin; 848e79055d6SMark Brown constraints->max_uV = cmax; 849e79055d6SMark Brown } 850e79055d6SMark Brown 851e79055d6SMark Brown /* voltage constraints are optional */ 852e79055d6SMark Brown if ((cmin == 0) && (cmax == 0)) 853e79055d6SMark Brown return 0; 854e79055d6SMark Brown 855e79055d6SMark Brown /* else require explicit machine-level constraints */ 856e79055d6SMark Brown if (cmin <= 0 || cmax <= 0 || cmax < cmin) { 8575da84fd9SJoe Perches rdev_err(rdev, "invalid voltage constraints\n"); 858e79055d6SMark Brown return -EINVAL; 859e79055d6SMark Brown } 860e79055d6SMark Brown 861e79055d6SMark Brown /* initial: [cmin..cmax] valid, [min_uV..max_uV] not */ 862e79055d6SMark Brown for (i = 0; i < count; i++) { 863e79055d6SMark Brown int value; 864e79055d6SMark Brown 865e79055d6SMark Brown value = ops->list_voltage(rdev, i); 866e79055d6SMark Brown if (value <= 0) 867e79055d6SMark Brown continue; 868e79055d6SMark Brown 869e79055d6SMark Brown /* maybe adjust [min_uV..max_uV] */ 870e79055d6SMark Brown if (value >= cmin && value < min_uV) 871e79055d6SMark Brown min_uV = value; 872e79055d6SMark Brown if (value <= cmax && value > max_uV) 873e79055d6SMark Brown max_uV = value; 874e79055d6SMark Brown } 875e79055d6SMark Brown 876e79055d6SMark Brown /* final: [min_uV..max_uV] valid iff constraints valid */ 877e79055d6SMark Brown if (max_uV < min_uV) { 8785da84fd9SJoe Perches rdev_err(rdev, "unsupportable voltage constraints\n"); 879e79055d6SMark Brown return -EINVAL; 880e79055d6SMark Brown } 881e79055d6SMark Brown 882e79055d6SMark Brown /* use regulator's subset of machine constraints */ 883e79055d6SMark Brown if (constraints->min_uV < min_uV) { 8845da84fd9SJoe Perches rdev_dbg(rdev, "override min_uV, %d -> %d\n", 8855da84fd9SJoe Perches constraints->min_uV, min_uV); 886e79055d6SMark Brown constraints->min_uV = min_uV; 887e79055d6SMark Brown } 888e79055d6SMark Brown if (constraints->max_uV > max_uV) { 8895da84fd9SJoe Perches rdev_dbg(rdev, "override max_uV, %d -> %d\n", 8905da84fd9SJoe Perches constraints->max_uV, max_uV); 891e79055d6SMark Brown constraints->max_uV = max_uV; 892e79055d6SMark Brown } 893e79055d6SMark Brown } 894e79055d6SMark Brown 895e79055d6SMark Brown return 0; 896e79055d6SMark Brown } 897e79055d6SMark Brown 898a5766f11SLiam Girdwood /** 899a5766f11SLiam Girdwood * set_machine_constraints - sets regulator constraints 90069279fb9SMark Brown * @rdev: regulator source 901c8e7e464SMark Brown * @constraints: constraints to apply 902a5766f11SLiam Girdwood * 903a5766f11SLiam Girdwood * Allows platform initialisation code to define and constrain 904a5766f11SLiam Girdwood * regulator circuits e.g. valid voltage/current ranges, etc. NOTE: 905a5766f11SLiam Girdwood * Constraints *must* be set by platform code in order for some 906a5766f11SLiam Girdwood * regulator operations to proceed i.e. set_voltage, set_current_limit, 907a5766f11SLiam Girdwood * set_mode. 908a5766f11SLiam Girdwood */ 909a5766f11SLiam Girdwood static int set_machine_constraints(struct regulator_dev *rdev, 910f8c12fe3SMark Brown const struct regulation_constraints *constraints) 911a5766f11SLiam Girdwood { 912a5766f11SLiam Girdwood int ret = 0; 913e5fda26cSMark Brown struct regulator_ops *ops = rdev->desc->ops; 914e06f5b4fSMark Brown 9159a8f5e07SMark Brown if (constraints) 916f8c12fe3SMark Brown rdev->constraints = kmemdup(constraints, sizeof(*constraints), 917f8c12fe3SMark Brown GFP_KERNEL); 9189a8f5e07SMark Brown else 9199a8f5e07SMark Brown rdev->constraints = kzalloc(sizeof(*constraints), 9209a8f5e07SMark Brown GFP_KERNEL); 921f8c12fe3SMark Brown if (!rdev->constraints) 922f8c12fe3SMark Brown return -ENOMEM; 923af5866c9SMark Brown 924f8c12fe3SMark Brown ret = machine_constraints_voltage(rdev, rdev->constraints); 925e79055d6SMark Brown if (ret != 0) 9263e2b9abdSMark Brown goto out; 9273e2b9abdSMark Brown 928a5766f11SLiam Girdwood /* do we need to setup our suspend state */ 9299a8f5e07SMark Brown if (rdev->constraints->initial_state) { 930f8c12fe3SMark Brown ret = suspend_prepare(rdev, rdev->constraints->initial_state); 931e06f5b4fSMark Brown if (ret < 0) { 9325da84fd9SJoe Perches rdev_err(rdev, "failed to set suspend state\n"); 933e06f5b4fSMark Brown goto out; 934e06f5b4fSMark Brown } 935e06f5b4fSMark Brown } 936a5766f11SLiam Girdwood 9379a8f5e07SMark Brown if (rdev->constraints->initial_mode) { 938a308466cSMark Brown if (!ops->set_mode) { 9395da84fd9SJoe Perches rdev_err(rdev, "no set_mode operation\n"); 940a308466cSMark Brown ret = -EINVAL; 941a308466cSMark Brown goto out; 942a308466cSMark Brown } 943a308466cSMark Brown 944f8c12fe3SMark Brown ret = ops->set_mode(rdev, rdev->constraints->initial_mode); 945a308466cSMark Brown if (ret < 0) { 9465da84fd9SJoe Perches rdev_err(rdev, "failed to set initial mode: %d\n", ret); 947a308466cSMark Brown goto out; 948a308466cSMark Brown } 949a308466cSMark Brown } 950a308466cSMark Brown 951cacf90f2SMark Brown /* If the constraints say the regulator should be on at this point 952cacf90f2SMark Brown * and we have control then make sure it is enabled. 953cacf90f2SMark Brown */ 954f8c12fe3SMark Brown if ((rdev->constraints->always_on || rdev->constraints->boot_on) && 955f8c12fe3SMark Brown ops->enable) { 956e5fda26cSMark Brown ret = ops->enable(rdev); 957e5fda26cSMark Brown if (ret < 0) { 9585da84fd9SJoe Perches rdev_err(rdev, "failed to enable\n"); 959e5fda26cSMark Brown goto out; 960e5fda26cSMark Brown } 961e5fda26cSMark Brown } 962e5fda26cSMark Brown 963a5766f11SLiam Girdwood print_constraints(rdev); 9641a6958e7SAxel Lin return 0; 965a5766f11SLiam Girdwood out: 9661a6958e7SAxel Lin kfree(rdev->constraints); 9671a6958e7SAxel Lin rdev->constraints = NULL; 968a5766f11SLiam Girdwood return ret; 969a5766f11SLiam Girdwood } 970a5766f11SLiam Girdwood 971a5766f11SLiam Girdwood /** 972a5766f11SLiam Girdwood * set_supply - set regulator supply regulator 97369279fb9SMark Brown * @rdev: regulator name 97469279fb9SMark Brown * @supply_rdev: supply regulator name 975a5766f11SLiam Girdwood * 976a5766f11SLiam Girdwood * Called by platform initialisation code to set the supply regulator for this 977a5766f11SLiam Girdwood * regulator. This ensures that a regulators supply will also be enabled by the 978a5766f11SLiam Girdwood * core if it's child is enabled. 979a5766f11SLiam Girdwood */ 980a5766f11SLiam Girdwood static int set_supply(struct regulator_dev *rdev, 981a5766f11SLiam Girdwood struct regulator_dev *supply_rdev) 982a5766f11SLiam Girdwood { 983a5766f11SLiam Girdwood int err; 984a5766f11SLiam Girdwood 9853801b86aSMark Brown rdev_info(rdev, "supplied by %s\n", rdev_get_name(supply_rdev)); 9863801b86aSMark Brown 9873801b86aSMark Brown rdev->supply = create_regulator(supply_rdev, &rdev->dev, "SUPPLY"); 98832c78de8SAxel Lin if (rdev->supply == NULL) { 98932c78de8SAxel Lin err = -ENOMEM; 990a5766f11SLiam Girdwood return err; 991a5766f11SLiam Girdwood } 992a5766f11SLiam Girdwood 9933801b86aSMark Brown return 0; 9943801b86aSMark Brown } 9953801b86aSMark Brown 996a5766f11SLiam Girdwood /** 99706c63f93SRandy Dunlap * set_consumer_device_supply - Bind a regulator to a symbolic supply 99869279fb9SMark Brown * @rdev: regulator source 99940f9244fSMark Brown * @consumer_dev_name: dev_name() string for device supply applies to 1000a5766f11SLiam Girdwood * @supply: symbolic name for supply 1001a5766f11SLiam Girdwood * 1002a5766f11SLiam Girdwood * Allows platform initialisation code to map physical regulator 1003a5766f11SLiam Girdwood * sources to symbolic names for supplies for use by devices. Devices 1004a5766f11SLiam Girdwood * should use these symbolic names to request regulators, avoiding the 1005a5766f11SLiam Girdwood * need to provide board-specific regulator names as platform data. 1006a5766f11SLiam Girdwood */ 1007a5766f11SLiam Girdwood static int set_consumer_device_supply(struct regulator_dev *rdev, 1008737f360dSMark Brown const char *consumer_dev_name, 100940f9244fSMark Brown const char *supply) 1010a5766f11SLiam Girdwood { 1011a5766f11SLiam Girdwood struct regulator_map *node; 10129ed2099eSMark Brown int has_dev; 1013a5766f11SLiam Girdwood 1014a5766f11SLiam Girdwood if (supply == NULL) 1015a5766f11SLiam Girdwood return -EINVAL; 1016a5766f11SLiam Girdwood 10179ed2099eSMark Brown if (consumer_dev_name != NULL) 10189ed2099eSMark Brown has_dev = 1; 10199ed2099eSMark Brown else 10209ed2099eSMark Brown has_dev = 0; 10219ed2099eSMark Brown 10226001e13cSDavid Brownell list_for_each_entry(node, ®ulator_map_list, list) { 102323b5cc2aSJani Nikula if (node->dev_name && consumer_dev_name) { 102423b5cc2aSJani Nikula if (strcmp(node->dev_name, consumer_dev_name) != 0) 10256001e13cSDavid Brownell continue; 102623b5cc2aSJani Nikula } else if (node->dev_name || consumer_dev_name) { 102723b5cc2aSJani Nikula continue; 102823b5cc2aSJani Nikula } 102923b5cc2aSJani Nikula 10306001e13cSDavid Brownell if (strcmp(node->supply, supply) != 0) 10316001e13cSDavid Brownell continue; 10326001e13cSDavid Brownell 1033737f360dSMark Brown pr_debug("%s: %s/%s is '%s' supply; fail %s/%s\n", 1034737f360dSMark Brown consumer_dev_name, 10356001e13cSDavid Brownell dev_name(&node->regulator->dev), 10366001e13cSDavid Brownell node->regulator->desc->name, 10376001e13cSDavid Brownell supply, 10381083c393SMark Brown dev_name(&rdev->dev), rdev_get_name(rdev)); 10396001e13cSDavid Brownell return -EBUSY; 10406001e13cSDavid Brownell } 10416001e13cSDavid Brownell 10429ed2099eSMark Brown node = kzalloc(sizeof(struct regulator_map), GFP_KERNEL); 1043a5766f11SLiam Girdwood if (node == NULL) 1044a5766f11SLiam Girdwood return -ENOMEM; 1045a5766f11SLiam Girdwood 1046a5766f11SLiam Girdwood node->regulator = rdev; 1047a5766f11SLiam Girdwood node->supply = supply; 1048a5766f11SLiam Girdwood 10499ed2099eSMark Brown if (has_dev) { 10509ed2099eSMark Brown node->dev_name = kstrdup(consumer_dev_name, GFP_KERNEL); 105140f9244fSMark Brown if (node->dev_name == NULL) { 105240f9244fSMark Brown kfree(node); 105340f9244fSMark Brown return -ENOMEM; 105440f9244fSMark Brown } 10559ed2099eSMark Brown } 105640f9244fSMark Brown 1057a5766f11SLiam Girdwood list_add(&node->list, ®ulator_map_list); 1058a5766f11SLiam Girdwood return 0; 1059a5766f11SLiam Girdwood } 1060a5766f11SLiam Girdwood 10610f1d747bSMike Rapoport static void unset_regulator_supplies(struct regulator_dev *rdev) 10620f1d747bSMike Rapoport { 10630f1d747bSMike Rapoport struct regulator_map *node, *n; 10640f1d747bSMike Rapoport 10650f1d747bSMike Rapoport list_for_each_entry_safe(node, n, ®ulator_map_list, list) { 10660f1d747bSMike Rapoport if (rdev == node->regulator) { 10670f1d747bSMike Rapoport list_del(&node->list); 106840f9244fSMark Brown kfree(node->dev_name); 10690f1d747bSMike Rapoport kfree(node); 10700f1d747bSMike Rapoport } 10710f1d747bSMike Rapoport } 10720f1d747bSMike Rapoport } 10730f1d747bSMike Rapoport 1074f5726ae3SMark Brown #define REG_STR_SIZE 64 1075414c70cbSLiam Girdwood 1076414c70cbSLiam Girdwood static struct regulator *create_regulator(struct regulator_dev *rdev, 1077414c70cbSLiam Girdwood struct device *dev, 1078414c70cbSLiam Girdwood const char *supply_name) 1079414c70cbSLiam Girdwood { 1080414c70cbSLiam Girdwood struct regulator *regulator; 1081414c70cbSLiam Girdwood char buf[REG_STR_SIZE]; 1082414c70cbSLiam Girdwood int err, size; 1083414c70cbSLiam Girdwood 1084414c70cbSLiam Girdwood regulator = kzalloc(sizeof(*regulator), GFP_KERNEL); 1085414c70cbSLiam Girdwood if (regulator == NULL) 1086414c70cbSLiam Girdwood return NULL; 1087414c70cbSLiam Girdwood 1088414c70cbSLiam Girdwood mutex_lock(&rdev->mutex); 1089414c70cbSLiam Girdwood regulator->rdev = rdev; 1090414c70cbSLiam Girdwood list_add(®ulator->list, &rdev->consumer_list); 1091414c70cbSLiam Girdwood 1092414c70cbSLiam Girdwood if (dev) { 1093414c70cbSLiam Girdwood /* create a 'requested_microamps_name' sysfs entry */ 1094e0eaedefSMark Brown size = scnprintf(buf, REG_STR_SIZE, 1095e0eaedefSMark Brown "microamps_requested_%s-%s", 1096e0eaedefSMark Brown dev_name(dev), supply_name); 1097414c70cbSLiam Girdwood if (size >= REG_STR_SIZE) 1098414c70cbSLiam Girdwood goto overflow_err; 1099414c70cbSLiam Girdwood 1100414c70cbSLiam Girdwood regulator->dev = dev; 11014f26a2abSAmeya Palande sysfs_attr_init(®ulator->dev_attr.attr); 1102414c70cbSLiam Girdwood regulator->dev_attr.attr.name = kstrdup(buf, GFP_KERNEL); 1103414c70cbSLiam Girdwood if (regulator->dev_attr.attr.name == NULL) 1104414c70cbSLiam Girdwood goto attr_name_err; 1105414c70cbSLiam Girdwood 1106414c70cbSLiam Girdwood regulator->dev_attr.attr.mode = 0444; 1107414c70cbSLiam Girdwood regulator->dev_attr.show = device_requested_uA_show; 1108414c70cbSLiam Girdwood err = device_create_file(dev, ®ulator->dev_attr); 1109414c70cbSLiam Girdwood if (err < 0) { 11105da84fd9SJoe Perches rdev_warn(rdev, "could not add regulator_dev requested microamps sysfs entry\n"); 1111414c70cbSLiam Girdwood goto attr_name_err; 1112414c70cbSLiam Girdwood } 1113414c70cbSLiam Girdwood 1114414c70cbSLiam Girdwood /* also add a link to the device sysfs entry */ 1115414c70cbSLiam Girdwood size = scnprintf(buf, REG_STR_SIZE, "%s-%s", 1116414c70cbSLiam Girdwood dev->kobj.name, supply_name); 1117414c70cbSLiam Girdwood if (size >= REG_STR_SIZE) 1118414c70cbSLiam Girdwood goto attr_err; 1119414c70cbSLiam Girdwood 1120414c70cbSLiam Girdwood regulator->supply_name = kstrdup(buf, GFP_KERNEL); 1121414c70cbSLiam Girdwood if (regulator->supply_name == NULL) 1122414c70cbSLiam Girdwood goto attr_err; 1123414c70cbSLiam Girdwood 1124414c70cbSLiam Girdwood err = sysfs_create_link(&rdev->dev.kobj, &dev->kobj, 1125414c70cbSLiam Girdwood buf); 1126414c70cbSLiam Girdwood if (err) { 11275da84fd9SJoe Perches rdev_warn(rdev, "could not add device link %s err %d\n", 11281d7372e1SDaniel Walker dev->kobj.name, err); 1129414c70cbSLiam Girdwood goto link_name_err; 1130414c70cbSLiam Girdwood } 11315de70519SMark Brown } else { 11325de70519SMark Brown regulator->supply_name = kstrdup(supply_name, GFP_KERNEL); 11335de70519SMark Brown if (regulator->supply_name == NULL) 11345de70519SMark Brown goto attr_err; 1135414c70cbSLiam Girdwood } 11365de70519SMark Brown 11375de70519SMark Brown regulator->debugfs = debugfs_create_dir(regulator->supply_name, 11385de70519SMark Brown rdev->debugfs); 113924751434SStephen Boyd if (!regulator->debugfs) { 11405de70519SMark Brown rdev_warn(rdev, "Failed to create debugfs directory\n"); 11415de70519SMark Brown } else { 11425de70519SMark Brown debugfs_create_u32("uA_load", 0444, regulator->debugfs, 11435de70519SMark Brown ®ulator->uA_load); 11445de70519SMark Brown debugfs_create_u32("min_uV", 0444, regulator->debugfs, 11455de70519SMark Brown ®ulator->min_uV); 11465de70519SMark Brown debugfs_create_u32("max_uV", 0444, regulator->debugfs, 11475de70519SMark Brown ®ulator->max_uV); 11485de70519SMark Brown } 11495de70519SMark Brown 1150414c70cbSLiam Girdwood mutex_unlock(&rdev->mutex); 1151414c70cbSLiam Girdwood return regulator; 1152414c70cbSLiam Girdwood link_name_err: 1153414c70cbSLiam Girdwood kfree(regulator->supply_name); 1154414c70cbSLiam Girdwood attr_err: 1155414c70cbSLiam Girdwood device_remove_file(regulator->dev, ®ulator->dev_attr); 1156414c70cbSLiam Girdwood attr_name_err: 1157414c70cbSLiam Girdwood kfree(regulator->dev_attr.attr.name); 1158414c70cbSLiam Girdwood overflow_err: 1159414c70cbSLiam Girdwood list_del(®ulator->list); 1160414c70cbSLiam Girdwood kfree(regulator); 1161414c70cbSLiam Girdwood mutex_unlock(&rdev->mutex); 1162414c70cbSLiam Girdwood return NULL; 1163414c70cbSLiam Girdwood } 1164414c70cbSLiam Girdwood 116531aae2beSMark Brown static int _regulator_get_enable_time(struct regulator_dev *rdev) 116631aae2beSMark Brown { 116731aae2beSMark Brown if (!rdev->desc->ops->enable_time) 116831aae2beSMark Brown return 0; 116931aae2beSMark Brown return rdev->desc->ops->enable_time(rdev); 117031aae2beSMark Brown } 117131aae2beSMark Brown 117269511a45SRajendra Nayak static struct regulator_dev *regulator_dev_lookup(struct device *dev, 117369511a45SRajendra Nayak const char *supply) 117469511a45SRajendra Nayak { 117569511a45SRajendra Nayak struct regulator_dev *r; 117669511a45SRajendra Nayak struct device_node *node; 117769511a45SRajendra Nayak 117869511a45SRajendra Nayak /* first do a dt based lookup */ 117969511a45SRajendra Nayak if (dev && dev->of_node) { 118069511a45SRajendra Nayak node = of_get_regulator(dev, supply); 118169511a45SRajendra Nayak if (node) 118269511a45SRajendra Nayak list_for_each_entry(r, ®ulator_list, list) 118369511a45SRajendra Nayak if (r->dev.parent && 118469511a45SRajendra Nayak node == r->dev.of_node) 118569511a45SRajendra Nayak return r; 118669511a45SRajendra Nayak } 118769511a45SRajendra Nayak 118869511a45SRajendra Nayak /* if not found, try doing it non-dt way */ 118969511a45SRajendra Nayak list_for_each_entry(r, ®ulator_list, list) 119069511a45SRajendra Nayak if (strcmp(rdev_get_name(r), supply) == 0) 119169511a45SRajendra Nayak return r; 119269511a45SRajendra Nayak 119369511a45SRajendra Nayak return NULL; 119469511a45SRajendra Nayak } 119569511a45SRajendra Nayak 11965ffbd136SMark Brown /* Internal regulator request function */ 11975ffbd136SMark Brown static struct regulator *_regulator_get(struct device *dev, const char *id, 11985ffbd136SMark Brown int exclusive) 1199414c70cbSLiam Girdwood { 1200414c70cbSLiam Girdwood struct regulator_dev *rdev; 1201414c70cbSLiam Girdwood struct regulator_map *map; 120204bf3011SMark Brown struct regulator *regulator = ERR_PTR(-EPROBE_DEFER); 120340f9244fSMark Brown const char *devname = NULL; 12045ffbd136SMark Brown int ret; 1205414c70cbSLiam Girdwood 1206414c70cbSLiam Girdwood if (id == NULL) { 12075da84fd9SJoe Perches pr_err("get() with no identifier\n"); 1208414c70cbSLiam Girdwood return regulator; 1209414c70cbSLiam Girdwood } 1210414c70cbSLiam Girdwood 121140f9244fSMark Brown if (dev) 121240f9244fSMark Brown devname = dev_name(dev); 121340f9244fSMark Brown 1214414c70cbSLiam Girdwood mutex_lock(®ulator_list_mutex); 1215414c70cbSLiam Girdwood 121669511a45SRajendra Nayak rdev = regulator_dev_lookup(dev, id); 121769511a45SRajendra Nayak if (rdev) 121869511a45SRajendra Nayak goto found; 121969511a45SRajendra Nayak 1220414c70cbSLiam Girdwood list_for_each_entry(map, ®ulator_map_list, list) { 122140f9244fSMark Brown /* If the mapping has a device set up it must match */ 122240f9244fSMark Brown if (map->dev_name && 122340f9244fSMark Brown (!devname || strcmp(map->dev_name, devname))) 122440f9244fSMark Brown continue; 122540f9244fSMark Brown 122640f9244fSMark Brown if (strcmp(map->supply, id) == 0) { 1227a5766f11SLiam Girdwood rdev = map->regulator; 1228414c70cbSLiam Girdwood goto found; 1229414c70cbSLiam Girdwood } 1230a5766f11SLiam Girdwood } 123134abbd68SMark Brown 1232688fe99aSMark Brown if (board_wants_dummy_regulator) { 1233688fe99aSMark Brown rdev = dummy_regulator_rdev; 1234688fe99aSMark Brown goto found; 1235688fe99aSMark Brown } 1236688fe99aSMark Brown 123734abbd68SMark Brown #ifdef CONFIG_REGULATOR_DUMMY 123834abbd68SMark Brown if (!devname) 123934abbd68SMark Brown devname = "deviceless"; 124034abbd68SMark Brown 124134abbd68SMark Brown /* If the board didn't flag that it was fully constrained then 124234abbd68SMark Brown * substitute in a dummy regulator so consumers can continue. 124334abbd68SMark Brown */ 124434abbd68SMark Brown if (!has_full_constraints) { 12455da84fd9SJoe Perches pr_warn("%s supply %s not found, using dummy regulator\n", 124634abbd68SMark Brown devname, id); 124734abbd68SMark Brown rdev = dummy_regulator_rdev; 124834abbd68SMark Brown goto found; 124934abbd68SMark Brown } 125034abbd68SMark Brown #endif 125134abbd68SMark Brown 1252414c70cbSLiam Girdwood mutex_unlock(®ulator_list_mutex); 1253414c70cbSLiam Girdwood return regulator; 1254414c70cbSLiam Girdwood 1255414c70cbSLiam Girdwood found: 12565ffbd136SMark Brown if (rdev->exclusive) { 12575ffbd136SMark Brown regulator = ERR_PTR(-EPERM); 12585ffbd136SMark Brown goto out; 12595ffbd136SMark Brown } 12605ffbd136SMark Brown 12615ffbd136SMark Brown if (exclusive && rdev->open_count) { 12625ffbd136SMark Brown regulator = ERR_PTR(-EBUSY); 12635ffbd136SMark Brown goto out; 12645ffbd136SMark Brown } 12655ffbd136SMark Brown 1266a5766f11SLiam Girdwood if (!try_module_get(rdev->owner)) 1267a5766f11SLiam Girdwood goto out; 1268a5766f11SLiam Girdwood 1269414c70cbSLiam Girdwood regulator = create_regulator(rdev, dev, id); 1270414c70cbSLiam Girdwood if (regulator == NULL) { 1271414c70cbSLiam Girdwood regulator = ERR_PTR(-ENOMEM); 1272414c70cbSLiam Girdwood module_put(rdev->owner); 1273bcda4321SAxel Lin goto out; 1274414c70cbSLiam Girdwood } 1275414c70cbSLiam Girdwood 12765ffbd136SMark Brown rdev->open_count++; 12775ffbd136SMark Brown if (exclusive) { 12785ffbd136SMark Brown rdev->exclusive = 1; 12795ffbd136SMark Brown 12805ffbd136SMark Brown ret = _regulator_is_enabled(rdev); 12815ffbd136SMark Brown if (ret > 0) 12825ffbd136SMark Brown rdev->use_count = 1; 12835ffbd136SMark Brown else 12845ffbd136SMark Brown rdev->use_count = 0; 12855ffbd136SMark Brown } 12865ffbd136SMark Brown 1287a5766f11SLiam Girdwood out: 1288414c70cbSLiam Girdwood mutex_unlock(®ulator_list_mutex); 12895ffbd136SMark Brown 1290414c70cbSLiam Girdwood return regulator; 1291414c70cbSLiam Girdwood } 12925ffbd136SMark Brown 12935ffbd136SMark Brown /** 12945ffbd136SMark Brown * regulator_get - lookup and obtain a reference to a regulator. 12955ffbd136SMark Brown * @dev: device for regulator "consumer" 12965ffbd136SMark Brown * @id: Supply name or regulator ID. 12975ffbd136SMark Brown * 12985ffbd136SMark Brown * Returns a struct regulator corresponding to the regulator producer, 12995ffbd136SMark Brown * or IS_ERR() condition containing errno. 13005ffbd136SMark Brown * 13015ffbd136SMark Brown * Use of supply names configured via regulator_set_device_supply() is 13025ffbd136SMark Brown * strongly encouraged. It is recommended that the supply name used 13035ffbd136SMark Brown * should match the name used for the supply and/or the relevant 13045ffbd136SMark Brown * device pins in the datasheet. 13055ffbd136SMark Brown */ 13065ffbd136SMark Brown struct regulator *regulator_get(struct device *dev, const char *id) 13075ffbd136SMark Brown { 13085ffbd136SMark Brown return _regulator_get(dev, id, 0); 13095ffbd136SMark Brown } 1310414c70cbSLiam Girdwood EXPORT_SYMBOL_GPL(regulator_get); 1311414c70cbSLiam Girdwood 1312070b9079SStephen Boyd static void devm_regulator_release(struct device *dev, void *res) 1313070b9079SStephen Boyd { 1314070b9079SStephen Boyd regulator_put(*(struct regulator **)res); 1315070b9079SStephen Boyd } 1316070b9079SStephen Boyd 1317070b9079SStephen Boyd /** 1318070b9079SStephen Boyd * devm_regulator_get - Resource managed regulator_get() 1319070b9079SStephen Boyd * @dev: device for regulator "consumer" 1320070b9079SStephen Boyd * @id: Supply name or regulator ID. 1321070b9079SStephen Boyd * 1322070b9079SStephen Boyd * Managed regulator_get(). Regulators returned from this function are 1323070b9079SStephen Boyd * automatically regulator_put() on driver detach. See regulator_get() for more 1324070b9079SStephen Boyd * information. 1325070b9079SStephen Boyd */ 1326070b9079SStephen Boyd struct regulator *devm_regulator_get(struct device *dev, const char *id) 1327070b9079SStephen Boyd { 1328070b9079SStephen Boyd struct regulator **ptr, *regulator; 1329070b9079SStephen Boyd 1330070b9079SStephen Boyd ptr = devres_alloc(devm_regulator_release, sizeof(*ptr), GFP_KERNEL); 1331070b9079SStephen Boyd if (!ptr) 1332070b9079SStephen Boyd return ERR_PTR(-ENOMEM); 1333070b9079SStephen Boyd 1334070b9079SStephen Boyd regulator = regulator_get(dev, id); 1335070b9079SStephen Boyd if (!IS_ERR(regulator)) { 1336070b9079SStephen Boyd *ptr = regulator; 1337070b9079SStephen Boyd devres_add(dev, ptr); 1338070b9079SStephen Boyd } else { 1339070b9079SStephen Boyd devres_free(ptr); 1340070b9079SStephen Boyd } 1341070b9079SStephen Boyd 1342070b9079SStephen Boyd return regulator; 1343070b9079SStephen Boyd } 1344070b9079SStephen Boyd EXPORT_SYMBOL_GPL(devm_regulator_get); 1345070b9079SStephen Boyd 1346414c70cbSLiam Girdwood /** 13475ffbd136SMark Brown * regulator_get_exclusive - obtain exclusive access to a regulator. 13485ffbd136SMark Brown * @dev: device for regulator "consumer" 13495ffbd136SMark Brown * @id: Supply name or regulator ID. 13505ffbd136SMark Brown * 13515ffbd136SMark Brown * Returns a struct regulator corresponding to the regulator producer, 13525ffbd136SMark Brown * or IS_ERR() condition containing errno. Other consumers will be 13535ffbd136SMark Brown * unable to obtain this reference is held and the use count for the 13545ffbd136SMark Brown * regulator will be initialised to reflect the current state of the 13555ffbd136SMark Brown * regulator. 13565ffbd136SMark Brown * 13575ffbd136SMark Brown * This is intended for use by consumers which cannot tolerate shared 13585ffbd136SMark Brown * use of the regulator such as those which need to force the 13595ffbd136SMark Brown * regulator off for correct operation of the hardware they are 13605ffbd136SMark Brown * controlling. 13615ffbd136SMark Brown * 13625ffbd136SMark Brown * Use of supply names configured via regulator_set_device_supply() is 13635ffbd136SMark Brown * strongly encouraged. It is recommended that the supply name used 13645ffbd136SMark Brown * should match the name used for the supply and/or the relevant 13655ffbd136SMark Brown * device pins in the datasheet. 13665ffbd136SMark Brown */ 13675ffbd136SMark Brown struct regulator *regulator_get_exclusive(struct device *dev, const char *id) 13685ffbd136SMark Brown { 13695ffbd136SMark Brown return _regulator_get(dev, id, 1); 13705ffbd136SMark Brown } 13715ffbd136SMark Brown EXPORT_SYMBOL_GPL(regulator_get_exclusive); 13725ffbd136SMark Brown 13735ffbd136SMark Brown /** 1374414c70cbSLiam Girdwood * regulator_put - "free" the regulator source 1375414c70cbSLiam Girdwood * @regulator: regulator source 1376414c70cbSLiam Girdwood * 1377414c70cbSLiam Girdwood * Note: drivers must ensure that all regulator_enable calls made on this 1378414c70cbSLiam Girdwood * regulator source are balanced by regulator_disable calls prior to calling 1379414c70cbSLiam Girdwood * this function. 1380414c70cbSLiam Girdwood */ 1381414c70cbSLiam Girdwood void regulator_put(struct regulator *regulator) 1382414c70cbSLiam Girdwood { 1383414c70cbSLiam Girdwood struct regulator_dev *rdev; 1384414c70cbSLiam Girdwood 1385414c70cbSLiam Girdwood if (regulator == NULL || IS_ERR(regulator)) 1386414c70cbSLiam Girdwood return; 1387414c70cbSLiam Girdwood 1388414c70cbSLiam Girdwood mutex_lock(®ulator_list_mutex); 1389414c70cbSLiam Girdwood rdev = regulator->rdev; 1390414c70cbSLiam Girdwood 13915de70519SMark Brown debugfs_remove_recursive(regulator->debugfs); 13925de70519SMark Brown 1393414c70cbSLiam Girdwood /* remove any sysfs entries */ 1394414c70cbSLiam Girdwood if (regulator->dev) { 1395414c70cbSLiam Girdwood sysfs_remove_link(&rdev->dev.kobj, regulator->supply_name); 1396414c70cbSLiam Girdwood device_remove_file(regulator->dev, ®ulator->dev_attr); 1397414c70cbSLiam Girdwood kfree(regulator->dev_attr.attr.name); 1398414c70cbSLiam Girdwood } 13995de70519SMark Brown kfree(regulator->supply_name); 1400414c70cbSLiam Girdwood list_del(®ulator->list); 1401414c70cbSLiam Girdwood kfree(regulator); 1402414c70cbSLiam Girdwood 14035ffbd136SMark Brown rdev->open_count--; 14045ffbd136SMark Brown rdev->exclusive = 0; 14055ffbd136SMark Brown 1406414c70cbSLiam Girdwood module_put(rdev->owner); 1407414c70cbSLiam Girdwood mutex_unlock(®ulator_list_mutex); 1408414c70cbSLiam Girdwood } 1409414c70cbSLiam Girdwood EXPORT_SYMBOL_GPL(regulator_put); 1410414c70cbSLiam Girdwood 1411d5ad34f7SMark Brown static int devm_regulator_match(struct device *dev, void *res, void *data) 1412d5ad34f7SMark Brown { 1413d5ad34f7SMark Brown struct regulator **r = res; 1414d5ad34f7SMark Brown if (!r || !*r) { 1415d5ad34f7SMark Brown WARN_ON(!r || !*r); 1416d5ad34f7SMark Brown return 0; 1417d5ad34f7SMark Brown } 1418d5ad34f7SMark Brown return *r == data; 1419d5ad34f7SMark Brown } 1420d5ad34f7SMark Brown 1421d5ad34f7SMark Brown /** 1422d5ad34f7SMark Brown * devm_regulator_put - Resource managed regulator_put() 1423d5ad34f7SMark Brown * @regulator: regulator to free 1424d5ad34f7SMark Brown * 1425d5ad34f7SMark Brown * Deallocate a regulator allocated with devm_regulator_get(). Normally 1426d5ad34f7SMark Brown * this function will not need to be called and the resource management 1427d5ad34f7SMark Brown * code will ensure that the resource is freed. 1428d5ad34f7SMark Brown */ 1429d5ad34f7SMark Brown void devm_regulator_put(struct regulator *regulator) 1430d5ad34f7SMark Brown { 1431d5ad34f7SMark Brown int rc; 1432d5ad34f7SMark Brown 1433d5ad34f7SMark Brown rc = devres_destroy(regulator->dev, devm_regulator_release, 1434d5ad34f7SMark Brown devm_regulator_match, regulator); 1435d5ad34f7SMark Brown WARN_ON(rc); 1436d5ad34f7SMark Brown } 1437d5ad34f7SMark Brown EXPORT_SYMBOL_GPL(devm_regulator_put); 1438d5ad34f7SMark Brown 14399a2372faSMark Brown static int _regulator_can_change_status(struct regulator_dev *rdev) 14409a2372faSMark Brown { 14419a2372faSMark Brown if (!rdev->constraints) 14429a2372faSMark Brown return 0; 14439a2372faSMark Brown 14449a2372faSMark Brown if (rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_STATUS) 14459a2372faSMark Brown return 1; 14469a2372faSMark Brown else 14479a2372faSMark Brown return 0; 14489a2372faSMark Brown } 14499a2372faSMark Brown 1450414c70cbSLiam Girdwood /* locks held by regulator_enable() */ 1451414c70cbSLiam Girdwood static int _regulator_enable(struct regulator_dev *rdev) 1452414c70cbSLiam Girdwood { 145331aae2beSMark Brown int ret, delay; 1454414c70cbSLiam Girdwood 1455414c70cbSLiam Girdwood /* check voltage and requested load before enabling */ 1456414c70cbSLiam Girdwood if (rdev->constraints && 14579a2372faSMark Brown (rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_DRMS)) 1458414c70cbSLiam Girdwood drms_uA_update(rdev); 1459414c70cbSLiam Girdwood 14609a2372faSMark Brown if (rdev->use_count == 0) { 14619a2372faSMark Brown /* The regulator may on if it's not switchable or left on */ 14629a2372faSMark Brown ret = _regulator_is_enabled(rdev); 14639a2372faSMark Brown if (ret == -EINVAL || ret == 0) { 14649a2372faSMark Brown if (!_regulator_can_change_status(rdev)) 14659a2372faSMark Brown return -EPERM; 14669a2372faSMark Brown 146731aae2beSMark Brown if (!rdev->desc->ops->enable) 146831aae2beSMark Brown return -EINVAL; 146931aae2beSMark Brown 147031aae2beSMark Brown /* Query before enabling in case configuration 147125985edcSLucas De Marchi * dependent. */ 147231aae2beSMark Brown ret = _regulator_get_enable_time(rdev); 147331aae2beSMark Brown if (ret >= 0) { 147431aae2beSMark Brown delay = ret; 147531aae2beSMark Brown } else { 14765da84fd9SJoe Perches rdev_warn(rdev, "enable_time() failed: %d\n", 147731aae2beSMark Brown ret); 147831aae2beSMark Brown delay = 0; 147931aae2beSMark Brown } 148031aae2beSMark Brown 148102fa3ec0SMark Brown trace_regulator_enable(rdev_get_name(rdev)); 148202fa3ec0SMark Brown 148331aae2beSMark Brown /* Allow the regulator to ramp; it would be useful 148431aae2beSMark Brown * to extend this for bulk operations so that the 148531aae2beSMark Brown * regulators can ramp together. */ 1486414c70cbSLiam Girdwood ret = rdev->desc->ops->enable(rdev); 14879a2372faSMark Brown if (ret < 0) 14889a2372faSMark Brown return ret; 148931aae2beSMark Brown 149002fa3ec0SMark Brown trace_regulator_enable_delay(rdev_get_name(rdev)); 149102fa3ec0SMark Brown 1492e36c1df8SAxel Lin if (delay >= 1000) { 149331aae2beSMark Brown mdelay(delay / 1000); 1494e36c1df8SAxel Lin udelay(delay % 1000); 1495e36c1df8SAxel Lin } else if (delay) { 149631aae2beSMark Brown udelay(delay); 1497e36c1df8SAxel Lin } 149831aae2beSMark Brown 149902fa3ec0SMark Brown trace_regulator_enable_complete(rdev_get_name(rdev)); 150002fa3ec0SMark Brown 1501a7433cffSLinus Walleij } else if (ret < 0) { 15025da84fd9SJoe Perches rdev_err(rdev, "is_enabled() failed: %d\n", ret); 1503414c70cbSLiam Girdwood return ret; 1504414c70cbSLiam Girdwood } 1505a7433cffSLinus Walleij /* Fallthrough on positive return values - already enabled */ 1506414c70cbSLiam Girdwood } 1507414c70cbSLiam Girdwood 15089a2372faSMark Brown rdev->use_count++; 15099a2372faSMark Brown 15109a2372faSMark Brown return 0; 1511414c70cbSLiam Girdwood } 1512414c70cbSLiam Girdwood 1513414c70cbSLiam Girdwood /** 1514414c70cbSLiam Girdwood * regulator_enable - enable regulator output 1515414c70cbSLiam Girdwood * @regulator: regulator source 1516414c70cbSLiam Girdwood * 1517cf7bbcdfSMark Brown * Request that the regulator be enabled with the regulator output at 1518cf7bbcdfSMark Brown * the predefined voltage or current value. Calls to regulator_enable() 1519cf7bbcdfSMark Brown * must be balanced with calls to regulator_disable(). 1520cf7bbcdfSMark Brown * 1521414c70cbSLiam Girdwood * NOTE: the output value can be set by other drivers, boot loader or may be 1522cf7bbcdfSMark Brown * hardwired in the regulator. 1523414c70cbSLiam Girdwood */ 1524414c70cbSLiam Girdwood int regulator_enable(struct regulator *regulator) 1525414c70cbSLiam Girdwood { 1526412aec61SDavid Brownell struct regulator_dev *rdev = regulator->rdev; 1527412aec61SDavid Brownell int ret = 0; 1528414c70cbSLiam Girdwood 15293801b86aSMark Brown if (rdev->supply) { 15303801b86aSMark Brown ret = regulator_enable(rdev->supply); 15313801b86aSMark Brown if (ret != 0) 15323801b86aSMark Brown return ret; 15333801b86aSMark Brown } 15343801b86aSMark Brown 1535412aec61SDavid Brownell mutex_lock(&rdev->mutex); 1536412aec61SDavid Brownell ret = _regulator_enable(rdev); 1537412aec61SDavid Brownell mutex_unlock(&rdev->mutex); 15383801b86aSMark Brown 1539d1685e4eSHeiko Stübner if (ret != 0 && rdev->supply) 15403801b86aSMark Brown regulator_disable(rdev->supply); 15413801b86aSMark Brown 1542414c70cbSLiam Girdwood return ret; 1543414c70cbSLiam Girdwood } 1544414c70cbSLiam Girdwood EXPORT_SYMBOL_GPL(regulator_enable); 1545414c70cbSLiam Girdwood 1546414c70cbSLiam Girdwood /* locks held by regulator_disable() */ 15473801b86aSMark Brown static int _regulator_disable(struct regulator_dev *rdev) 1548414c70cbSLiam Girdwood { 1549414c70cbSLiam Girdwood int ret = 0; 1550414c70cbSLiam Girdwood 1551cd94b505SDavid Brownell if (WARN(rdev->use_count <= 0, 155243e7ee33SJoe Perches "unbalanced disables for %s\n", rdev_get_name(rdev))) 1553cd94b505SDavid Brownell return -EIO; 1554cd94b505SDavid Brownell 1555414c70cbSLiam Girdwood /* are we the last user and permitted to disable ? */ 155660ef66fcSMark Brown if (rdev->use_count == 1 && 155760ef66fcSMark Brown (rdev->constraints && !rdev->constraints->always_on)) { 1558414c70cbSLiam Girdwood 1559414c70cbSLiam Girdwood /* we are last user */ 15609a2372faSMark Brown if (_regulator_can_change_status(rdev) && 15619a2372faSMark Brown rdev->desc->ops->disable) { 156202fa3ec0SMark Brown trace_regulator_disable(rdev_get_name(rdev)); 156302fa3ec0SMark Brown 1564414c70cbSLiam Girdwood ret = rdev->desc->ops->disable(rdev); 1565414c70cbSLiam Girdwood if (ret < 0) { 15665da84fd9SJoe Perches rdev_err(rdev, "failed to disable\n"); 1567414c70cbSLiam Girdwood return ret; 1568414c70cbSLiam Girdwood } 156984b68263SMark Brown 157002fa3ec0SMark Brown trace_regulator_disable_complete(rdev_get_name(rdev)); 157102fa3ec0SMark Brown 157284b68263SMark Brown _notifier_call_chain(rdev, REGULATOR_EVENT_DISABLE, 157384b68263SMark Brown NULL); 1574414c70cbSLiam Girdwood } 1575414c70cbSLiam Girdwood 1576414c70cbSLiam Girdwood rdev->use_count = 0; 1577414c70cbSLiam Girdwood } else if (rdev->use_count > 1) { 1578414c70cbSLiam Girdwood 1579414c70cbSLiam Girdwood if (rdev->constraints && 1580414c70cbSLiam Girdwood (rdev->constraints->valid_ops_mask & 1581414c70cbSLiam Girdwood REGULATOR_CHANGE_DRMS)) 1582414c70cbSLiam Girdwood drms_uA_update(rdev); 1583414c70cbSLiam Girdwood 1584414c70cbSLiam Girdwood rdev->use_count--; 1585414c70cbSLiam Girdwood } 15863801b86aSMark Brown 1587414c70cbSLiam Girdwood return ret; 1588414c70cbSLiam Girdwood } 1589414c70cbSLiam Girdwood 1590414c70cbSLiam Girdwood /** 1591414c70cbSLiam Girdwood * regulator_disable - disable regulator output 1592414c70cbSLiam Girdwood * @regulator: regulator source 1593414c70cbSLiam Girdwood * 1594cf7bbcdfSMark Brown * Disable the regulator output voltage or current. Calls to 1595cf7bbcdfSMark Brown * regulator_enable() must be balanced with calls to 1596cf7bbcdfSMark Brown * regulator_disable(). 159769279fb9SMark Brown * 1598414c70cbSLiam Girdwood * NOTE: this will only disable the regulator output if no other consumer 1599cf7bbcdfSMark Brown * devices have it enabled, the regulator device supports disabling and 1600cf7bbcdfSMark Brown * machine constraints permit this operation. 1601414c70cbSLiam Girdwood */ 1602414c70cbSLiam Girdwood int regulator_disable(struct regulator *regulator) 1603414c70cbSLiam Girdwood { 1604412aec61SDavid Brownell struct regulator_dev *rdev = regulator->rdev; 1605412aec61SDavid Brownell int ret = 0; 1606414c70cbSLiam Girdwood 1607412aec61SDavid Brownell mutex_lock(&rdev->mutex); 16083801b86aSMark Brown ret = _regulator_disable(rdev); 1609412aec61SDavid Brownell mutex_unlock(&rdev->mutex); 16108cbf811dSJeffrey Carlyle 16113801b86aSMark Brown if (ret == 0 && rdev->supply) 16123801b86aSMark Brown regulator_disable(rdev->supply); 16138cbf811dSJeffrey Carlyle 1614414c70cbSLiam Girdwood return ret; 1615414c70cbSLiam Girdwood } 1616414c70cbSLiam Girdwood EXPORT_SYMBOL_GPL(regulator_disable); 1617414c70cbSLiam Girdwood 1618414c70cbSLiam Girdwood /* locks held by regulator_force_disable() */ 16193801b86aSMark Brown static int _regulator_force_disable(struct regulator_dev *rdev) 1620414c70cbSLiam Girdwood { 1621414c70cbSLiam Girdwood int ret = 0; 1622414c70cbSLiam Girdwood 1623414c70cbSLiam Girdwood /* force disable */ 1624414c70cbSLiam Girdwood if (rdev->desc->ops->disable) { 1625414c70cbSLiam Girdwood /* ah well, who wants to live forever... */ 1626414c70cbSLiam Girdwood ret = rdev->desc->ops->disable(rdev); 1627414c70cbSLiam Girdwood if (ret < 0) { 16285da84fd9SJoe Perches rdev_err(rdev, "failed to force disable\n"); 1629414c70cbSLiam Girdwood return ret; 1630414c70cbSLiam Girdwood } 1631414c70cbSLiam Girdwood /* notify other consumers that power has been forced off */ 163284b68263SMark Brown _notifier_call_chain(rdev, REGULATOR_EVENT_FORCE_DISABLE | 163384b68263SMark Brown REGULATOR_EVENT_DISABLE, NULL); 1634414c70cbSLiam Girdwood } 1635414c70cbSLiam Girdwood 1636414c70cbSLiam Girdwood return ret; 1637414c70cbSLiam Girdwood } 1638414c70cbSLiam Girdwood 1639414c70cbSLiam Girdwood /** 1640414c70cbSLiam Girdwood * regulator_force_disable - force disable regulator output 1641414c70cbSLiam Girdwood * @regulator: regulator source 1642414c70cbSLiam Girdwood * 1643414c70cbSLiam Girdwood * Forcibly disable the regulator output voltage or current. 1644414c70cbSLiam Girdwood * NOTE: this *will* disable the regulator output even if other consumer 1645414c70cbSLiam Girdwood * devices have it enabled. This should be used for situations when device 1646414c70cbSLiam Girdwood * damage will likely occur if the regulator is not disabled (e.g. over temp). 1647414c70cbSLiam Girdwood */ 1648414c70cbSLiam Girdwood int regulator_force_disable(struct regulator *regulator) 1649414c70cbSLiam Girdwood { 165082d15839SMark Brown struct regulator_dev *rdev = regulator->rdev; 1651414c70cbSLiam Girdwood int ret; 1652414c70cbSLiam Girdwood 165382d15839SMark Brown mutex_lock(&rdev->mutex); 1654414c70cbSLiam Girdwood regulator->uA_load = 0; 16553801b86aSMark Brown ret = _regulator_force_disable(regulator->rdev); 165682d15839SMark Brown mutex_unlock(&rdev->mutex); 16578cbf811dSJeffrey Carlyle 16583801b86aSMark Brown if (rdev->supply) 16593801b86aSMark Brown while (rdev->open_count--) 16603801b86aSMark Brown regulator_disable(rdev->supply); 16618cbf811dSJeffrey Carlyle 1662414c70cbSLiam Girdwood return ret; 1663414c70cbSLiam Girdwood } 1664414c70cbSLiam Girdwood EXPORT_SYMBOL_GPL(regulator_force_disable); 1665414c70cbSLiam Girdwood 1666da07ecd9SMark Brown static void regulator_disable_work(struct work_struct *work) 1667da07ecd9SMark Brown { 1668da07ecd9SMark Brown struct regulator_dev *rdev = container_of(work, struct regulator_dev, 1669da07ecd9SMark Brown disable_work.work); 1670da07ecd9SMark Brown int count, i, ret; 1671da07ecd9SMark Brown 1672da07ecd9SMark Brown mutex_lock(&rdev->mutex); 1673da07ecd9SMark Brown 1674da07ecd9SMark Brown BUG_ON(!rdev->deferred_disables); 1675da07ecd9SMark Brown 1676da07ecd9SMark Brown count = rdev->deferred_disables; 1677da07ecd9SMark Brown rdev->deferred_disables = 0; 1678da07ecd9SMark Brown 1679da07ecd9SMark Brown for (i = 0; i < count; i++) { 1680da07ecd9SMark Brown ret = _regulator_disable(rdev); 1681da07ecd9SMark Brown if (ret != 0) 1682da07ecd9SMark Brown rdev_err(rdev, "Deferred disable failed: %d\n", ret); 1683da07ecd9SMark Brown } 1684da07ecd9SMark Brown 1685da07ecd9SMark Brown mutex_unlock(&rdev->mutex); 1686da07ecd9SMark Brown 1687da07ecd9SMark Brown if (rdev->supply) { 1688da07ecd9SMark Brown for (i = 0; i < count; i++) { 1689da07ecd9SMark Brown ret = regulator_disable(rdev->supply); 1690da07ecd9SMark Brown if (ret != 0) { 1691da07ecd9SMark Brown rdev_err(rdev, 1692da07ecd9SMark Brown "Supply disable failed: %d\n", ret); 1693da07ecd9SMark Brown } 1694da07ecd9SMark Brown } 1695da07ecd9SMark Brown } 1696da07ecd9SMark Brown } 1697da07ecd9SMark Brown 1698da07ecd9SMark Brown /** 1699da07ecd9SMark Brown * regulator_disable_deferred - disable regulator output with delay 1700da07ecd9SMark Brown * @regulator: regulator source 1701da07ecd9SMark Brown * @ms: miliseconds until the regulator is disabled 1702da07ecd9SMark Brown * 1703da07ecd9SMark Brown * Execute regulator_disable() on the regulator after a delay. This 1704da07ecd9SMark Brown * is intended for use with devices that require some time to quiesce. 1705da07ecd9SMark Brown * 1706da07ecd9SMark Brown * NOTE: this will only disable the regulator output if no other consumer 1707da07ecd9SMark Brown * devices have it enabled, the regulator device supports disabling and 1708da07ecd9SMark Brown * machine constraints permit this operation. 1709da07ecd9SMark Brown */ 1710da07ecd9SMark Brown int regulator_disable_deferred(struct regulator *regulator, int ms) 1711da07ecd9SMark Brown { 1712da07ecd9SMark Brown struct regulator_dev *rdev = regulator->rdev; 1713aa59802dSMark Brown int ret; 1714da07ecd9SMark Brown 1715da07ecd9SMark Brown mutex_lock(&rdev->mutex); 1716da07ecd9SMark Brown rdev->deferred_disables++; 1717da07ecd9SMark Brown mutex_unlock(&rdev->mutex); 1718da07ecd9SMark Brown 1719aa59802dSMark Brown ret = schedule_delayed_work(&rdev->disable_work, 1720da07ecd9SMark Brown msecs_to_jiffies(ms)); 1721aa59802dSMark Brown if (ret < 0) 1722aa59802dSMark Brown return ret; 1723aa59802dSMark Brown else 1724aa59802dSMark Brown return 0; 1725da07ecd9SMark Brown } 1726da07ecd9SMark Brown EXPORT_SYMBOL_GPL(regulator_disable_deferred); 1727da07ecd9SMark Brown 1728cd6dffb4SMark Brown /** 1729cd6dffb4SMark Brown * regulator_is_enabled_regmap - standard is_enabled() for regmap users 1730cd6dffb4SMark Brown * 1731cd6dffb4SMark Brown * @rdev: regulator to operate on 1732cd6dffb4SMark Brown * 1733cd6dffb4SMark Brown * Regulators that use regmap for their register I/O can set the 1734cd6dffb4SMark Brown * enable_reg and enable_mask fields in their descriptor and then use 1735cd6dffb4SMark Brown * this as their is_enabled operation, saving some code. 1736cd6dffb4SMark Brown */ 1737cd6dffb4SMark Brown int regulator_is_enabled_regmap(struct regulator_dev *rdev) 1738cd6dffb4SMark Brown { 1739cd6dffb4SMark Brown unsigned int val; 1740cd6dffb4SMark Brown int ret; 1741cd6dffb4SMark Brown 1742cd6dffb4SMark Brown ret = regmap_read(rdev->regmap, rdev->desc->enable_reg, &val); 1743cd6dffb4SMark Brown if (ret != 0) 1744cd6dffb4SMark Brown return ret; 1745cd6dffb4SMark Brown 1746cd6dffb4SMark Brown return (val & rdev->desc->enable_mask) != 0; 1747cd6dffb4SMark Brown } 1748cd6dffb4SMark Brown EXPORT_SYMBOL_GPL(regulator_is_enabled_regmap); 1749cd6dffb4SMark Brown 1750cd6dffb4SMark Brown /** 1751cd6dffb4SMark Brown * regulator_enable_regmap - standard enable() for regmap users 1752cd6dffb4SMark Brown * 1753cd6dffb4SMark Brown * @rdev: regulator to operate on 1754cd6dffb4SMark Brown * 1755cd6dffb4SMark Brown * Regulators that use regmap for their register I/O can set the 1756cd6dffb4SMark Brown * enable_reg and enable_mask fields in their descriptor and then use 1757cd6dffb4SMark Brown * this as their enable() operation, saving some code. 1758cd6dffb4SMark Brown */ 1759cd6dffb4SMark Brown int regulator_enable_regmap(struct regulator_dev *rdev) 1760cd6dffb4SMark Brown { 1761cd6dffb4SMark Brown return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, 1762cd6dffb4SMark Brown rdev->desc->enable_mask, 1763cd6dffb4SMark Brown rdev->desc->enable_mask); 1764cd6dffb4SMark Brown } 1765cd6dffb4SMark Brown EXPORT_SYMBOL_GPL(regulator_enable_regmap); 1766cd6dffb4SMark Brown 1767cd6dffb4SMark Brown /** 1768cd6dffb4SMark Brown * regulator_disable_regmap - standard disable() for regmap users 1769cd6dffb4SMark Brown * 1770cd6dffb4SMark Brown * @rdev: regulator to operate on 1771cd6dffb4SMark Brown * 1772cd6dffb4SMark Brown * Regulators that use regmap for their register I/O can set the 1773cd6dffb4SMark Brown * enable_reg and enable_mask fields in their descriptor and then use 1774cd6dffb4SMark Brown * this as their disable() operation, saving some code. 1775cd6dffb4SMark Brown */ 1776cd6dffb4SMark Brown int regulator_disable_regmap(struct regulator_dev *rdev) 1777cd6dffb4SMark Brown { 1778cd6dffb4SMark Brown return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, 1779cd6dffb4SMark Brown rdev->desc->enable_mask, 0); 1780cd6dffb4SMark Brown } 1781cd6dffb4SMark Brown EXPORT_SYMBOL_GPL(regulator_disable_regmap); 1782cd6dffb4SMark Brown 1783414c70cbSLiam Girdwood static int _regulator_is_enabled(struct regulator_dev *rdev) 1784414c70cbSLiam Girdwood { 17859a7f6a4cSMark Brown /* If we don't know then assume that the regulator is always on */ 17869332546fSMark Brown if (!rdev->desc->ops->is_enabled) 17879a7f6a4cSMark Brown return 1; 1788414c70cbSLiam Girdwood 17899332546fSMark Brown return rdev->desc->ops->is_enabled(rdev); 1790414c70cbSLiam Girdwood } 1791414c70cbSLiam Girdwood 1792414c70cbSLiam Girdwood /** 1793414c70cbSLiam Girdwood * regulator_is_enabled - is the regulator output enabled 1794414c70cbSLiam Girdwood * @regulator: regulator source 1795414c70cbSLiam Girdwood * 1796412aec61SDavid Brownell * Returns positive if the regulator driver backing the source/client 1797412aec61SDavid Brownell * has requested that the device be enabled, zero if it hasn't, else a 1798412aec61SDavid Brownell * negative errno code. 1799412aec61SDavid Brownell * 1800412aec61SDavid Brownell * Note that the device backing this regulator handle can have multiple 1801412aec61SDavid Brownell * users, so it might be enabled even if regulator_enable() was never 1802412aec61SDavid Brownell * called for this particular source. 1803414c70cbSLiam Girdwood */ 1804414c70cbSLiam Girdwood int regulator_is_enabled(struct regulator *regulator) 1805414c70cbSLiam Girdwood { 18069332546fSMark Brown int ret; 18079332546fSMark Brown 18089332546fSMark Brown mutex_lock(®ulator->rdev->mutex); 18099332546fSMark Brown ret = _regulator_is_enabled(regulator->rdev); 18109332546fSMark Brown mutex_unlock(®ulator->rdev->mutex); 18119332546fSMark Brown 18129332546fSMark Brown return ret; 1813414c70cbSLiam Girdwood } 1814414c70cbSLiam Girdwood EXPORT_SYMBOL_GPL(regulator_is_enabled); 1815414c70cbSLiam Girdwood 1816414c70cbSLiam Girdwood /** 18174367cfdcSDavid Brownell * regulator_count_voltages - count regulator_list_voltage() selectors 18184367cfdcSDavid Brownell * @regulator: regulator source 18194367cfdcSDavid Brownell * 18204367cfdcSDavid Brownell * Returns number of selectors, or negative errno. Selectors are 18214367cfdcSDavid Brownell * numbered starting at zero, and typically correspond to bitfields 18224367cfdcSDavid Brownell * in hardware registers. 18234367cfdcSDavid Brownell */ 18244367cfdcSDavid Brownell int regulator_count_voltages(struct regulator *regulator) 18254367cfdcSDavid Brownell { 18264367cfdcSDavid Brownell struct regulator_dev *rdev = regulator->rdev; 18274367cfdcSDavid Brownell 18284367cfdcSDavid Brownell return rdev->desc->n_voltages ? : -EINVAL; 18294367cfdcSDavid Brownell } 18304367cfdcSDavid Brownell EXPORT_SYMBOL_GPL(regulator_count_voltages); 18314367cfdcSDavid Brownell 18324367cfdcSDavid Brownell /** 18334367cfdcSDavid Brownell * regulator_list_voltage - enumerate supported voltages 18344367cfdcSDavid Brownell * @regulator: regulator source 18354367cfdcSDavid Brownell * @selector: identify voltage to list 18364367cfdcSDavid Brownell * Context: can sleep 18374367cfdcSDavid Brownell * 18384367cfdcSDavid Brownell * Returns a voltage that can be passed to @regulator_set_voltage(), 183988393161SThomas Weber * zero if this selector code can't be used on this system, or a 18404367cfdcSDavid Brownell * negative errno. 18414367cfdcSDavid Brownell */ 18424367cfdcSDavid Brownell int regulator_list_voltage(struct regulator *regulator, unsigned selector) 18434367cfdcSDavid Brownell { 18444367cfdcSDavid Brownell struct regulator_dev *rdev = regulator->rdev; 18454367cfdcSDavid Brownell struct regulator_ops *ops = rdev->desc->ops; 18464367cfdcSDavid Brownell int ret; 18474367cfdcSDavid Brownell 18484367cfdcSDavid Brownell if (!ops->list_voltage || selector >= rdev->desc->n_voltages) 18494367cfdcSDavid Brownell return -EINVAL; 18504367cfdcSDavid Brownell 18514367cfdcSDavid Brownell mutex_lock(&rdev->mutex); 18524367cfdcSDavid Brownell ret = ops->list_voltage(rdev, selector); 18534367cfdcSDavid Brownell mutex_unlock(&rdev->mutex); 18544367cfdcSDavid Brownell 18554367cfdcSDavid Brownell if (ret > 0) { 18564367cfdcSDavid Brownell if (ret < rdev->constraints->min_uV) 18574367cfdcSDavid Brownell ret = 0; 18584367cfdcSDavid Brownell else if (ret > rdev->constraints->max_uV) 18594367cfdcSDavid Brownell ret = 0; 18604367cfdcSDavid Brownell } 18614367cfdcSDavid Brownell 18624367cfdcSDavid Brownell return ret; 18634367cfdcSDavid Brownell } 18644367cfdcSDavid Brownell EXPORT_SYMBOL_GPL(regulator_list_voltage); 18654367cfdcSDavid Brownell 18664367cfdcSDavid Brownell /** 1867a7a1ad90SMark Brown * regulator_is_supported_voltage - check if a voltage range can be supported 1868a7a1ad90SMark Brown * 1869a7a1ad90SMark Brown * @regulator: Regulator to check. 1870a7a1ad90SMark Brown * @min_uV: Minimum required voltage in uV. 1871a7a1ad90SMark Brown * @max_uV: Maximum required voltage in uV. 1872a7a1ad90SMark Brown * 1873a7a1ad90SMark Brown * Returns a boolean or a negative error code. 1874a7a1ad90SMark Brown */ 1875a7a1ad90SMark Brown int regulator_is_supported_voltage(struct regulator *regulator, 1876a7a1ad90SMark Brown int min_uV, int max_uV) 1877a7a1ad90SMark Brown { 1878a7a1ad90SMark Brown int i, voltages, ret; 1879a7a1ad90SMark Brown 1880a7a1ad90SMark Brown ret = regulator_count_voltages(regulator); 1881a7a1ad90SMark Brown if (ret < 0) 1882a7a1ad90SMark Brown return ret; 1883a7a1ad90SMark Brown voltages = ret; 1884a7a1ad90SMark Brown 1885a7a1ad90SMark Brown for (i = 0; i < voltages; i++) { 1886a7a1ad90SMark Brown ret = regulator_list_voltage(regulator, i); 1887a7a1ad90SMark Brown 1888a7a1ad90SMark Brown if (ret >= min_uV && ret <= max_uV) 1889a7a1ad90SMark Brown return 1; 1890a7a1ad90SMark Brown } 1891a7a1ad90SMark Brown 1892a7a1ad90SMark Brown return 0; 1893a7a1ad90SMark Brown } 1894a398eaa2SMark Brown EXPORT_SYMBOL_GPL(regulator_is_supported_voltage); 1895a7a1ad90SMark Brown 18964ab5b3d9SMark Brown /** 18974ab5b3d9SMark Brown * regulator_get_voltage_sel_regmap - standard get_voltage_sel for regmap users 18984ab5b3d9SMark Brown * 18994ab5b3d9SMark Brown * @rdev: regulator to operate on 19004ab5b3d9SMark Brown * 19014ab5b3d9SMark Brown * Regulators that use regmap for their register I/O can set the 19024ab5b3d9SMark Brown * vsel_reg and vsel_mask fields in their descriptor and then use this 19034ab5b3d9SMark Brown * as their get_voltage_vsel operation, saving some code. 19044ab5b3d9SMark Brown */ 19054ab5b3d9SMark Brown int regulator_get_voltage_sel_regmap(struct regulator_dev *rdev) 19064ab5b3d9SMark Brown { 19074ab5b3d9SMark Brown unsigned int val; 19084ab5b3d9SMark Brown int ret; 19094ab5b3d9SMark Brown 19104ab5b3d9SMark Brown ret = regmap_read(rdev->regmap, rdev->desc->vsel_reg, &val); 19114ab5b3d9SMark Brown if (ret != 0) 19124ab5b3d9SMark Brown return ret; 19134ab5b3d9SMark Brown 19144ab5b3d9SMark Brown val &= rdev->desc->vsel_mask; 19154ab5b3d9SMark Brown val >>= ffs(rdev->desc->vsel_mask) - 1; 19164ab5b3d9SMark Brown 19174ab5b3d9SMark Brown return val; 19184ab5b3d9SMark Brown } 19194ab5b3d9SMark Brown EXPORT_SYMBOL_GPL(regulator_get_voltage_sel_regmap); 19204ab5b3d9SMark Brown 19214ab5b3d9SMark Brown /** 19224ab5b3d9SMark Brown * regulator_set_voltage_sel_regmap - standard set_voltage_sel for regmap users 19234ab5b3d9SMark Brown * 19244ab5b3d9SMark Brown * @rdev: regulator to operate on 19254ab5b3d9SMark Brown * @sel: Selector to set 19264ab5b3d9SMark Brown * 19274ab5b3d9SMark Brown * Regulators that use regmap for their register I/O can set the 19284ab5b3d9SMark Brown * vsel_reg and vsel_mask fields in their descriptor and then use this 19294ab5b3d9SMark Brown * as their set_voltage_vsel operation, saving some code. 19304ab5b3d9SMark Brown */ 19314ab5b3d9SMark Brown int regulator_set_voltage_sel_regmap(struct regulator_dev *rdev, unsigned sel) 19324ab5b3d9SMark Brown { 19334ab5b3d9SMark Brown sel <<= ffs(rdev->desc->vsel_mask) - 1; 19344ab5b3d9SMark Brown 19354ab5b3d9SMark Brown return regmap_update_bits(rdev->regmap, rdev->desc->vsel_reg, 19364ab5b3d9SMark Brown rdev->desc->vsel_mask, sel); 19374ab5b3d9SMark Brown } 19384ab5b3d9SMark Brown EXPORT_SYMBOL_GPL(regulator_set_voltage_sel_regmap); 19394ab5b3d9SMark Brown 194075790251SMark Brown static int _regulator_do_set_voltage(struct regulator_dev *rdev, 194175790251SMark Brown int min_uV, int max_uV) 194275790251SMark Brown { 194375790251SMark Brown int ret; 194477af1b26SLinus Walleij int delay = 0; 194575790251SMark Brown unsigned int selector; 194675790251SMark Brown 194775790251SMark Brown trace_regulator_set_voltage(rdev_get_name(rdev), min_uV, max_uV); 194875790251SMark Brown 1949bf5892a8SMark Brown min_uV += rdev->constraints->uV_offset; 1950bf5892a8SMark Brown max_uV += rdev->constraints->uV_offset; 1951bf5892a8SMark Brown 195275790251SMark Brown if (rdev->desc->ops->set_voltage) { 195375790251SMark Brown ret = rdev->desc->ops->set_voltage(rdev, min_uV, max_uV, 195475790251SMark Brown &selector); 195575790251SMark Brown 195675790251SMark Brown if (rdev->desc->ops->list_voltage) 195775790251SMark Brown selector = rdev->desc->ops->list_voltage(rdev, 195875790251SMark Brown selector); 195975790251SMark Brown else 196075790251SMark Brown selector = -1; 1961e8eef82bSMark Brown } else if (rdev->desc->ops->set_voltage_sel) { 1962e8eef82bSMark Brown int best_val = INT_MAX; 1963e8eef82bSMark Brown int i; 1964e8eef82bSMark Brown 1965e8eef82bSMark Brown selector = 0; 1966e8eef82bSMark Brown 1967e8eef82bSMark Brown /* Find the smallest voltage that falls within the specified 1968e8eef82bSMark Brown * range. 1969e8eef82bSMark Brown */ 1970e8eef82bSMark Brown for (i = 0; i < rdev->desc->n_voltages; i++) { 1971e8eef82bSMark Brown ret = rdev->desc->ops->list_voltage(rdev, i); 1972e8eef82bSMark Brown if (ret < 0) 1973e8eef82bSMark Brown continue; 1974e8eef82bSMark Brown 1975e8eef82bSMark Brown if (ret < best_val && ret >= min_uV && ret <= max_uV) { 1976e8eef82bSMark Brown best_val = ret; 1977e8eef82bSMark Brown selector = i; 1978e8eef82bSMark Brown } 1979e8eef82bSMark Brown } 1980e8eef82bSMark Brown 198177af1b26SLinus Walleij /* 198277af1b26SLinus Walleij * If we can't obtain the old selector there is not enough 198377af1b26SLinus Walleij * info to call set_voltage_time_sel(). 198477af1b26SLinus Walleij */ 198577af1b26SLinus Walleij if (rdev->desc->ops->set_voltage_time_sel && 198677af1b26SLinus Walleij rdev->desc->ops->get_voltage_sel) { 198777af1b26SLinus Walleij unsigned int old_selector = 0; 198877af1b26SLinus Walleij 198977af1b26SLinus Walleij ret = rdev->desc->ops->get_voltage_sel(rdev); 199077af1b26SLinus Walleij if (ret < 0) 199177af1b26SLinus Walleij return ret; 199277af1b26SLinus Walleij old_selector = ret; 199307351233SAxel Lin ret = rdev->desc->ops->set_voltage_time_sel(rdev, 199477af1b26SLinus Walleij old_selector, selector); 199507351233SAxel Lin if (ret < 0) 199607351233SAxel Lin rdev_warn(rdev, "set_voltage_time_sel() failed: %d\n", ret); 199707351233SAxel Lin else 199807351233SAxel Lin delay = ret; 199977af1b26SLinus Walleij } 200077af1b26SLinus Walleij 2001e8eef82bSMark Brown if (best_val != INT_MAX) { 2002e8eef82bSMark Brown ret = rdev->desc->ops->set_voltage_sel(rdev, selector); 2003e8eef82bSMark Brown selector = best_val; 2004e8eef82bSMark Brown } else { 2005e8eef82bSMark Brown ret = -EINVAL; 2006e8eef82bSMark Brown } 200775790251SMark Brown } else { 200875790251SMark Brown ret = -EINVAL; 200975790251SMark Brown } 201075790251SMark Brown 201177af1b26SLinus Walleij /* Insert any necessary delays */ 201277af1b26SLinus Walleij if (delay >= 1000) { 201377af1b26SLinus Walleij mdelay(delay / 1000); 201477af1b26SLinus Walleij udelay(delay % 1000); 201577af1b26SLinus Walleij } else if (delay) { 201677af1b26SLinus Walleij udelay(delay); 201777af1b26SLinus Walleij } 201877af1b26SLinus Walleij 2019ded06a52SMark Brown if (ret == 0) 2020ded06a52SMark Brown _notifier_call_chain(rdev, REGULATOR_EVENT_VOLTAGE_CHANGE, 2021ded06a52SMark Brown NULL); 2022ded06a52SMark Brown 202375790251SMark Brown trace_regulator_set_voltage_complete(rdev_get_name(rdev), selector); 202475790251SMark Brown 202575790251SMark Brown return ret; 202675790251SMark Brown } 202775790251SMark Brown 2028a7a1ad90SMark Brown /** 2029414c70cbSLiam Girdwood * regulator_set_voltage - set regulator output voltage 2030414c70cbSLiam Girdwood * @regulator: regulator source 2031414c70cbSLiam Girdwood * @min_uV: Minimum required voltage in uV 2032414c70cbSLiam Girdwood * @max_uV: Maximum acceptable voltage in uV 2033414c70cbSLiam Girdwood * 2034414c70cbSLiam Girdwood * Sets a voltage regulator to the desired output voltage. This can be set 2035414c70cbSLiam Girdwood * during any regulator state. IOW, regulator can be disabled or enabled. 2036414c70cbSLiam Girdwood * 2037414c70cbSLiam Girdwood * If the regulator is enabled then the voltage will change to the new value 2038414c70cbSLiam Girdwood * immediately otherwise if the regulator is disabled the regulator will 2039414c70cbSLiam Girdwood * output at the new voltage when enabled. 2040414c70cbSLiam Girdwood * 2041414c70cbSLiam Girdwood * NOTE: If the regulator is shared between several devices then the lowest 2042414c70cbSLiam Girdwood * request voltage that meets the system constraints will be used. 204369279fb9SMark Brown * Regulator system constraints must be set for this regulator before 2044414c70cbSLiam Girdwood * calling this function otherwise this call will fail. 2045414c70cbSLiam Girdwood */ 2046414c70cbSLiam Girdwood int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV) 2047414c70cbSLiam Girdwood { 2048414c70cbSLiam Girdwood struct regulator_dev *rdev = regulator->rdev; 204995a3c23aSMark Brown int ret = 0; 2050414c70cbSLiam Girdwood 2051414c70cbSLiam Girdwood mutex_lock(&rdev->mutex); 2052414c70cbSLiam Girdwood 205395a3c23aSMark Brown /* If we're setting the same range as last time the change 205495a3c23aSMark Brown * should be a noop (some cpufreq implementations use the same 205595a3c23aSMark Brown * voltage for multiple frequencies, for example). 205695a3c23aSMark Brown */ 205795a3c23aSMark Brown if (regulator->min_uV == min_uV && regulator->max_uV == max_uV) 205895a3c23aSMark Brown goto out; 205995a3c23aSMark Brown 2060414c70cbSLiam Girdwood /* sanity check */ 2061e8eef82bSMark Brown if (!rdev->desc->ops->set_voltage && 2062e8eef82bSMark Brown !rdev->desc->ops->set_voltage_sel) { 2063414c70cbSLiam Girdwood ret = -EINVAL; 2064414c70cbSLiam Girdwood goto out; 2065414c70cbSLiam Girdwood } 2066414c70cbSLiam Girdwood 2067414c70cbSLiam Girdwood /* constraints check */ 2068414c70cbSLiam Girdwood ret = regulator_check_voltage(rdev, &min_uV, &max_uV); 2069414c70cbSLiam Girdwood if (ret < 0) 2070414c70cbSLiam Girdwood goto out; 2071414c70cbSLiam Girdwood regulator->min_uV = min_uV; 2072414c70cbSLiam Girdwood regulator->max_uV = max_uV; 20733a93f2a9SMark Brown 207405fda3b1SThomas Petazzoni ret = regulator_check_consumers(rdev, &min_uV, &max_uV); 207505fda3b1SThomas Petazzoni if (ret < 0) 207605fda3b1SThomas Petazzoni goto out; 207705fda3b1SThomas Petazzoni 207875790251SMark Brown ret = _regulator_do_set_voltage(rdev, min_uV, max_uV); 207902fa3ec0SMark Brown 2080414c70cbSLiam Girdwood out: 2081414c70cbSLiam Girdwood mutex_unlock(&rdev->mutex); 2082414c70cbSLiam Girdwood return ret; 2083414c70cbSLiam Girdwood } 2084414c70cbSLiam Girdwood EXPORT_SYMBOL_GPL(regulator_set_voltage); 2085414c70cbSLiam Girdwood 2086606a2562SMark Brown /** 208788cd222bSLinus Walleij * regulator_set_voltage_time - get raise/fall time 208888cd222bSLinus Walleij * @regulator: regulator source 208988cd222bSLinus Walleij * @old_uV: starting voltage in microvolts 209088cd222bSLinus Walleij * @new_uV: target voltage in microvolts 209188cd222bSLinus Walleij * 209288cd222bSLinus Walleij * Provided with the starting and ending voltage, this function attempts to 209388cd222bSLinus Walleij * calculate the time in microseconds required to rise or fall to this new 209488cd222bSLinus Walleij * voltage. 209588cd222bSLinus Walleij */ 209688cd222bSLinus Walleij int regulator_set_voltage_time(struct regulator *regulator, 209788cd222bSLinus Walleij int old_uV, int new_uV) 209888cd222bSLinus Walleij { 209988cd222bSLinus Walleij struct regulator_dev *rdev = regulator->rdev; 210088cd222bSLinus Walleij struct regulator_ops *ops = rdev->desc->ops; 210188cd222bSLinus Walleij int old_sel = -1; 210288cd222bSLinus Walleij int new_sel = -1; 210388cd222bSLinus Walleij int voltage; 210488cd222bSLinus Walleij int i; 210588cd222bSLinus Walleij 210688cd222bSLinus Walleij /* Currently requires operations to do this */ 210788cd222bSLinus Walleij if (!ops->list_voltage || !ops->set_voltage_time_sel 210888cd222bSLinus Walleij || !rdev->desc->n_voltages) 210988cd222bSLinus Walleij return -EINVAL; 211088cd222bSLinus Walleij 211188cd222bSLinus Walleij for (i = 0; i < rdev->desc->n_voltages; i++) { 211288cd222bSLinus Walleij /* We only look for exact voltage matches here */ 211388cd222bSLinus Walleij voltage = regulator_list_voltage(regulator, i); 211488cd222bSLinus Walleij if (voltage < 0) 211588cd222bSLinus Walleij return -EINVAL; 211688cd222bSLinus Walleij if (voltage == 0) 211788cd222bSLinus Walleij continue; 211888cd222bSLinus Walleij if (voltage == old_uV) 211988cd222bSLinus Walleij old_sel = i; 212088cd222bSLinus Walleij if (voltage == new_uV) 212188cd222bSLinus Walleij new_sel = i; 212288cd222bSLinus Walleij } 212388cd222bSLinus Walleij 212488cd222bSLinus Walleij if (old_sel < 0 || new_sel < 0) 212588cd222bSLinus Walleij return -EINVAL; 212688cd222bSLinus Walleij 212788cd222bSLinus Walleij return ops->set_voltage_time_sel(rdev, old_sel, new_sel); 212888cd222bSLinus Walleij } 212988cd222bSLinus Walleij EXPORT_SYMBOL_GPL(regulator_set_voltage_time); 213088cd222bSLinus Walleij 213188cd222bSLinus Walleij /** 2132606a2562SMark Brown * regulator_sync_voltage - re-apply last regulator output voltage 2133606a2562SMark Brown * @regulator: regulator source 2134606a2562SMark Brown * 2135606a2562SMark Brown * Re-apply the last configured voltage. This is intended to be used 2136606a2562SMark Brown * where some external control source the consumer is cooperating with 2137606a2562SMark Brown * has caused the configured voltage to change. 2138606a2562SMark Brown */ 2139606a2562SMark Brown int regulator_sync_voltage(struct regulator *regulator) 2140606a2562SMark Brown { 2141606a2562SMark Brown struct regulator_dev *rdev = regulator->rdev; 2142606a2562SMark Brown int ret, min_uV, max_uV; 2143606a2562SMark Brown 2144606a2562SMark Brown mutex_lock(&rdev->mutex); 2145606a2562SMark Brown 2146606a2562SMark Brown if (!rdev->desc->ops->set_voltage && 2147606a2562SMark Brown !rdev->desc->ops->set_voltage_sel) { 2148606a2562SMark Brown ret = -EINVAL; 2149606a2562SMark Brown goto out; 2150606a2562SMark Brown } 2151606a2562SMark Brown 2152606a2562SMark Brown /* This is only going to work if we've had a voltage configured. */ 2153606a2562SMark Brown if (!regulator->min_uV && !regulator->max_uV) { 2154606a2562SMark Brown ret = -EINVAL; 2155606a2562SMark Brown goto out; 2156606a2562SMark Brown } 2157606a2562SMark Brown 2158606a2562SMark Brown min_uV = regulator->min_uV; 2159606a2562SMark Brown max_uV = regulator->max_uV; 2160606a2562SMark Brown 2161606a2562SMark Brown /* This should be a paranoia check... */ 2162606a2562SMark Brown ret = regulator_check_voltage(rdev, &min_uV, &max_uV); 2163606a2562SMark Brown if (ret < 0) 2164606a2562SMark Brown goto out; 2165606a2562SMark Brown 2166606a2562SMark Brown ret = regulator_check_consumers(rdev, &min_uV, &max_uV); 2167606a2562SMark Brown if (ret < 0) 2168606a2562SMark Brown goto out; 2169606a2562SMark Brown 2170606a2562SMark Brown ret = _regulator_do_set_voltage(rdev, min_uV, max_uV); 2171606a2562SMark Brown 2172606a2562SMark Brown out: 2173606a2562SMark Brown mutex_unlock(&rdev->mutex); 2174606a2562SMark Brown return ret; 2175606a2562SMark Brown } 2176606a2562SMark Brown EXPORT_SYMBOL_GPL(regulator_sync_voltage); 2177606a2562SMark Brown 2178414c70cbSLiam Girdwood static int _regulator_get_voltage(struct regulator_dev *rdev) 2179414c70cbSLiam Girdwood { 2180bf5892a8SMark Brown int sel, ret; 2181476c2d83SMark Brown 2182476c2d83SMark Brown if (rdev->desc->ops->get_voltage_sel) { 2183476c2d83SMark Brown sel = rdev->desc->ops->get_voltage_sel(rdev); 2184476c2d83SMark Brown if (sel < 0) 2185476c2d83SMark Brown return sel; 2186bf5892a8SMark Brown ret = rdev->desc->ops->list_voltage(rdev, sel); 2187cb220d16SAxel Lin } else if (rdev->desc->ops->get_voltage) { 2188bf5892a8SMark Brown ret = rdev->desc->ops->get_voltage(rdev); 2189cb220d16SAxel Lin } else { 2190414c70cbSLiam Girdwood return -EINVAL; 2191cb220d16SAxel Lin } 2192bf5892a8SMark Brown 2193cb220d16SAxel Lin if (ret < 0) 2194cb220d16SAxel Lin return ret; 2195bf5892a8SMark Brown return ret - rdev->constraints->uV_offset; 2196414c70cbSLiam Girdwood } 2197414c70cbSLiam Girdwood 2198414c70cbSLiam Girdwood /** 2199414c70cbSLiam Girdwood * regulator_get_voltage - get regulator output voltage 2200414c70cbSLiam Girdwood * @regulator: regulator source 2201414c70cbSLiam Girdwood * 2202414c70cbSLiam Girdwood * This returns the current regulator voltage in uV. 2203414c70cbSLiam Girdwood * 2204414c70cbSLiam Girdwood * NOTE: If the regulator is disabled it will return the voltage value. This 2205414c70cbSLiam Girdwood * function should not be used to determine regulator state. 2206414c70cbSLiam Girdwood */ 2207414c70cbSLiam Girdwood int regulator_get_voltage(struct regulator *regulator) 2208414c70cbSLiam Girdwood { 2209414c70cbSLiam Girdwood int ret; 2210414c70cbSLiam Girdwood 2211414c70cbSLiam Girdwood mutex_lock(®ulator->rdev->mutex); 2212414c70cbSLiam Girdwood 2213414c70cbSLiam Girdwood ret = _regulator_get_voltage(regulator->rdev); 2214414c70cbSLiam Girdwood 2215414c70cbSLiam Girdwood mutex_unlock(®ulator->rdev->mutex); 2216414c70cbSLiam Girdwood 2217414c70cbSLiam Girdwood return ret; 2218414c70cbSLiam Girdwood } 2219414c70cbSLiam Girdwood EXPORT_SYMBOL_GPL(regulator_get_voltage); 2220414c70cbSLiam Girdwood 2221414c70cbSLiam Girdwood /** 2222414c70cbSLiam Girdwood * regulator_set_current_limit - set regulator output current limit 2223414c70cbSLiam Girdwood * @regulator: regulator source 2224414c70cbSLiam Girdwood * @min_uA: Minimuum supported current in uA 2225414c70cbSLiam Girdwood * @max_uA: Maximum supported current in uA 2226414c70cbSLiam Girdwood * 2227414c70cbSLiam Girdwood * Sets current sink to the desired output current. This can be set during 2228414c70cbSLiam Girdwood * any regulator state. IOW, regulator can be disabled or enabled. 2229414c70cbSLiam Girdwood * 2230414c70cbSLiam Girdwood * If the regulator is enabled then the current will change to the new value 2231414c70cbSLiam Girdwood * immediately otherwise if the regulator is disabled the regulator will 2232414c70cbSLiam Girdwood * output at the new current when enabled. 2233414c70cbSLiam Girdwood * 2234414c70cbSLiam Girdwood * NOTE: Regulator system constraints must be set for this regulator before 2235414c70cbSLiam Girdwood * calling this function otherwise this call will fail. 2236414c70cbSLiam Girdwood */ 2237414c70cbSLiam Girdwood int regulator_set_current_limit(struct regulator *regulator, 2238414c70cbSLiam Girdwood int min_uA, int max_uA) 2239414c70cbSLiam Girdwood { 2240414c70cbSLiam Girdwood struct regulator_dev *rdev = regulator->rdev; 2241414c70cbSLiam Girdwood int ret; 2242414c70cbSLiam Girdwood 2243414c70cbSLiam Girdwood mutex_lock(&rdev->mutex); 2244414c70cbSLiam Girdwood 2245414c70cbSLiam Girdwood /* sanity check */ 2246414c70cbSLiam Girdwood if (!rdev->desc->ops->set_current_limit) { 2247414c70cbSLiam Girdwood ret = -EINVAL; 2248414c70cbSLiam Girdwood goto out; 2249414c70cbSLiam Girdwood } 2250414c70cbSLiam Girdwood 2251414c70cbSLiam Girdwood /* constraints check */ 2252414c70cbSLiam Girdwood ret = regulator_check_current_limit(rdev, &min_uA, &max_uA); 2253414c70cbSLiam Girdwood if (ret < 0) 2254414c70cbSLiam Girdwood goto out; 2255414c70cbSLiam Girdwood 2256414c70cbSLiam Girdwood ret = rdev->desc->ops->set_current_limit(rdev, min_uA, max_uA); 2257414c70cbSLiam Girdwood out: 2258414c70cbSLiam Girdwood mutex_unlock(&rdev->mutex); 2259414c70cbSLiam Girdwood return ret; 2260414c70cbSLiam Girdwood } 2261414c70cbSLiam Girdwood EXPORT_SYMBOL_GPL(regulator_set_current_limit); 2262414c70cbSLiam Girdwood 2263414c70cbSLiam Girdwood static int _regulator_get_current_limit(struct regulator_dev *rdev) 2264414c70cbSLiam Girdwood { 2265414c70cbSLiam Girdwood int ret; 2266414c70cbSLiam Girdwood 2267414c70cbSLiam Girdwood mutex_lock(&rdev->mutex); 2268414c70cbSLiam Girdwood 2269414c70cbSLiam Girdwood /* sanity check */ 2270414c70cbSLiam Girdwood if (!rdev->desc->ops->get_current_limit) { 2271414c70cbSLiam Girdwood ret = -EINVAL; 2272414c70cbSLiam Girdwood goto out; 2273414c70cbSLiam Girdwood } 2274414c70cbSLiam Girdwood 2275414c70cbSLiam Girdwood ret = rdev->desc->ops->get_current_limit(rdev); 2276414c70cbSLiam Girdwood out: 2277414c70cbSLiam Girdwood mutex_unlock(&rdev->mutex); 2278414c70cbSLiam Girdwood return ret; 2279414c70cbSLiam Girdwood } 2280414c70cbSLiam Girdwood 2281414c70cbSLiam Girdwood /** 2282414c70cbSLiam Girdwood * regulator_get_current_limit - get regulator output current 2283414c70cbSLiam Girdwood * @regulator: regulator source 2284414c70cbSLiam Girdwood * 2285414c70cbSLiam Girdwood * This returns the current supplied by the specified current sink in uA. 2286414c70cbSLiam Girdwood * 2287414c70cbSLiam Girdwood * NOTE: If the regulator is disabled it will return the current value. This 2288414c70cbSLiam Girdwood * function should not be used to determine regulator state. 2289414c70cbSLiam Girdwood */ 2290414c70cbSLiam Girdwood int regulator_get_current_limit(struct regulator *regulator) 2291414c70cbSLiam Girdwood { 2292414c70cbSLiam Girdwood return _regulator_get_current_limit(regulator->rdev); 2293414c70cbSLiam Girdwood } 2294414c70cbSLiam Girdwood EXPORT_SYMBOL_GPL(regulator_get_current_limit); 2295414c70cbSLiam Girdwood 2296414c70cbSLiam Girdwood /** 2297414c70cbSLiam Girdwood * regulator_set_mode - set regulator operating mode 2298414c70cbSLiam Girdwood * @regulator: regulator source 2299414c70cbSLiam Girdwood * @mode: operating mode - one of the REGULATOR_MODE constants 2300414c70cbSLiam Girdwood * 2301414c70cbSLiam Girdwood * Set regulator operating mode to increase regulator efficiency or improve 2302414c70cbSLiam Girdwood * regulation performance. 2303414c70cbSLiam Girdwood * 2304414c70cbSLiam Girdwood * NOTE: Regulator system constraints must be set for this regulator before 2305414c70cbSLiam Girdwood * calling this function otherwise this call will fail. 2306414c70cbSLiam Girdwood */ 2307414c70cbSLiam Girdwood int regulator_set_mode(struct regulator *regulator, unsigned int mode) 2308414c70cbSLiam Girdwood { 2309414c70cbSLiam Girdwood struct regulator_dev *rdev = regulator->rdev; 2310414c70cbSLiam Girdwood int ret; 2311500b4ac9SSundar R Iyer int regulator_curr_mode; 2312414c70cbSLiam Girdwood 2313414c70cbSLiam Girdwood mutex_lock(&rdev->mutex); 2314414c70cbSLiam Girdwood 2315414c70cbSLiam Girdwood /* sanity check */ 2316414c70cbSLiam Girdwood if (!rdev->desc->ops->set_mode) { 2317414c70cbSLiam Girdwood ret = -EINVAL; 2318414c70cbSLiam Girdwood goto out; 2319414c70cbSLiam Girdwood } 2320414c70cbSLiam Girdwood 2321500b4ac9SSundar R Iyer /* return if the same mode is requested */ 2322500b4ac9SSundar R Iyer if (rdev->desc->ops->get_mode) { 2323500b4ac9SSundar R Iyer regulator_curr_mode = rdev->desc->ops->get_mode(rdev); 2324500b4ac9SSundar R Iyer if (regulator_curr_mode == mode) { 2325500b4ac9SSundar R Iyer ret = 0; 2326500b4ac9SSundar R Iyer goto out; 2327500b4ac9SSundar R Iyer } 2328500b4ac9SSundar R Iyer } 2329500b4ac9SSundar R Iyer 2330414c70cbSLiam Girdwood /* constraints check */ 233122c51b47SAxel Lin ret = regulator_mode_constrain(rdev, &mode); 2332414c70cbSLiam Girdwood if (ret < 0) 2333414c70cbSLiam Girdwood goto out; 2334414c70cbSLiam Girdwood 2335414c70cbSLiam Girdwood ret = rdev->desc->ops->set_mode(rdev, mode); 2336414c70cbSLiam Girdwood out: 2337414c70cbSLiam Girdwood mutex_unlock(&rdev->mutex); 2338414c70cbSLiam Girdwood return ret; 2339414c70cbSLiam Girdwood } 2340414c70cbSLiam Girdwood EXPORT_SYMBOL_GPL(regulator_set_mode); 2341414c70cbSLiam Girdwood 2342414c70cbSLiam Girdwood static unsigned int _regulator_get_mode(struct regulator_dev *rdev) 2343414c70cbSLiam Girdwood { 2344414c70cbSLiam Girdwood int ret; 2345414c70cbSLiam Girdwood 2346414c70cbSLiam Girdwood mutex_lock(&rdev->mutex); 2347414c70cbSLiam Girdwood 2348414c70cbSLiam Girdwood /* sanity check */ 2349414c70cbSLiam Girdwood if (!rdev->desc->ops->get_mode) { 2350414c70cbSLiam Girdwood ret = -EINVAL; 2351414c70cbSLiam Girdwood goto out; 2352414c70cbSLiam Girdwood } 2353414c70cbSLiam Girdwood 2354414c70cbSLiam Girdwood ret = rdev->desc->ops->get_mode(rdev); 2355414c70cbSLiam Girdwood out: 2356414c70cbSLiam Girdwood mutex_unlock(&rdev->mutex); 2357414c70cbSLiam Girdwood return ret; 2358414c70cbSLiam Girdwood } 2359414c70cbSLiam Girdwood 2360414c70cbSLiam Girdwood /** 2361414c70cbSLiam Girdwood * regulator_get_mode - get regulator operating mode 2362414c70cbSLiam Girdwood * @regulator: regulator source 2363414c70cbSLiam Girdwood * 2364414c70cbSLiam Girdwood * Get the current regulator operating mode. 2365414c70cbSLiam Girdwood */ 2366414c70cbSLiam Girdwood unsigned int regulator_get_mode(struct regulator *regulator) 2367414c70cbSLiam Girdwood { 2368414c70cbSLiam Girdwood return _regulator_get_mode(regulator->rdev); 2369414c70cbSLiam Girdwood } 2370414c70cbSLiam Girdwood EXPORT_SYMBOL_GPL(regulator_get_mode); 2371414c70cbSLiam Girdwood 2372414c70cbSLiam Girdwood /** 2373414c70cbSLiam Girdwood * regulator_set_optimum_mode - set regulator optimum operating mode 2374414c70cbSLiam Girdwood * @regulator: regulator source 2375414c70cbSLiam Girdwood * @uA_load: load current 2376414c70cbSLiam Girdwood * 2377414c70cbSLiam Girdwood * Notifies the regulator core of a new device load. This is then used by 2378414c70cbSLiam Girdwood * DRMS (if enabled by constraints) to set the most efficient regulator 2379414c70cbSLiam Girdwood * operating mode for the new regulator loading. 2380414c70cbSLiam Girdwood * 2381414c70cbSLiam Girdwood * Consumer devices notify their supply regulator of the maximum power 2382414c70cbSLiam Girdwood * they will require (can be taken from device datasheet in the power 2383414c70cbSLiam Girdwood * consumption tables) when they change operational status and hence power 2384414c70cbSLiam Girdwood * state. Examples of operational state changes that can affect power 2385414c70cbSLiam Girdwood * consumption are :- 2386414c70cbSLiam Girdwood * 2387414c70cbSLiam Girdwood * o Device is opened / closed. 2388414c70cbSLiam Girdwood * o Device I/O is about to begin or has just finished. 2389414c70cbSLiam Girdwood * o Device is idling in between work. 2390414c70cbSLiam Girdwood * 2391414c70cbSLiam Girdwood * This information is also exported via sysfs to userspace. 2392414c70cbSLiam Girdwood * 2393414c70cbSLiam Girdwood * DRMS will sum the total requested load on the regulator and change 2394414c70cbSLiam Girdwood * to the most efficient operating mode if platform constraints allow. 2395414c70cbSLiam Girdwood * 2396414c70cbSLiam Girdwood * Returns the new regulator mode or error. 2397414c70cbSLiam Girdwood */ 2398414c70cbSLiam Girdwood int regulator_set_optimum_mode(struct regulator *regulator, int uA_load) 2399414c70cbSLiam Girdwood { 2400414c70cbSLiam Girdwood struct regulator_dev *rdev = regulator->rdev; 2401414c70cbSLiam Girdwood struct regulator *consumer; 2402414c70cbSLiam Girdwood int ret, output_uV, input_uV, total_uA_load = 0; 2403414c70cbSLiam Girdwood unsigned int mode; 2404414c70cbSLiam Girdwood 2405414c70cbSLiam Girdwood mutex_lock(&rdev->mutex); 2406414c70cbSLiam Girdwood 2407a4b41483SMark Brown /* 2408a4b41483SMark Brown * first check to see if we can set modes at all, otherwise just 2409a4b41483SMark Brown * tell the consumer everything is OK. 2410a4b41483SMark Brown */ 2411414c70cbSLiam Girdwood regulator->uA_load = uA_load; 2412414c70cbSLiam Girdwood ret = regulator_check_drms(rdev); 2413a4b41483SMark Brown if (ret < 0) { 2414a4b41483SMark Brown ret = 0; 2415414c70cbSLiam Girdwood goto out; 2416a4b41483SMark Brown } 2417414c70cbSLiam Girdwood 2418414c70cbSLiam Girdwood if (!rdev->desc->ops->get_optimum_mode) 2419414c70cbSLiam Girdwood goto out; 2420414c70cbSLiam Girdwood 2421a4b41483SMark Brown /* 2422a4b41483SMark Brown * we can actually do this so any errors are indicators of 2423a4b41483SMark Brown * potential real failure. 2424a4b41483SMark Brown */ 2425a4b41483SMark Brown ret = -EINVAL; 2426a4b41483SMark Brown 2427414c70cbSLiam Girdwood /* get output voltage */ 24281bf5a1f8SMark Brown output_uV = _regulator_get_voltage(rdev); 2429414c70cbSLiam Girdwood if (output_uV <= 0) { 24305da84fd9SJoe Perches rdev_err(rdev, "invalid output voltage found\n"); 2431414c70cbSLiam Girdwood goto out; 2432414c70cbSLiam Girdwood } 2433414c70cbSLiam Girdwood 2434414c70cbSLiam Girdwood /* get input voltage */ 24351bf5a1f8SMark Brown input_uV = 0; 24361bf5a1f8SMark Brown if (rdev->supply) 24373801b86aSMark Brown input_uV = regulator_get_voltage(rdev->supply); 24381bf5a1f8SMark Brown if (input_uV <= 0) 2439414c70cbSLiam Girdwood input_uV = rdev->constraints->input_uV; 2440414c70cbSLiam Girdwood if (input_uV <= 0) { 24415da84fd9SJoe Perches rdev_err(rdev, "invalid input voltage found\n"); 2442414c70cbSLiam Girdwood goto out; 2443414c70cbSLiam Girdwood } 2444414c70cbSLiam Girdwood 2445414c70cbSLiam Girdwood /* calc total requested load for this regulator */ 2446414c70cbSLiam Girdwood list_for_each_entry(consumer, &rdev->consumer_list, list) 2447414c70cbSLiam Girdwood total_uA_load += consumer->uA_load; 2448414c70cbSLiam Girdwood 2449414c70cbSLiam Girdwood mode = rdev->desc->ops->get_optimum_mode(rdev, 2450414c70cbSLiam Girdwood input_uV, output_uV, 2451414c70cbSLiam Girdwood total_uA_load); 24522c608234SMark Brown ret = regulator_mode_constrain(rdev, &mode); 2453e573520bSDavid Brownell if (ret < 0) { 24545da84fd9SJoe Perches rdev_err(rdev, "failed to get optimum mode @ %d uA %d -> %d uV\n", 2455414c70cbSLiam Girdwood total_uA_load, input_uV, output_uV); 2456414c70cbSLiam Girdwood goto out; 2457414c70cbSLiam Girdwood } 2458414c70cbSLiam Girdwood 2459414c70cbSLiam Girdwood ret = rdev->desc->ops->set_mode(rdev, mode); 2460e573520bSDavid Brownell if (ret < 0) { 24615da84fd9SJoe Perches rdev_err(rdev, "failed to set optimum mode %x\n", mode); 2462414c70cbSLiam Girdwood goto out; 2463414c70cbSLiam Girdwood } 2464414c70cbSLiam Girdwood ret = mode; 2465414c70cbSLiam Girdwood out: 2466414c70cbSLiam Girdwood mutex_unlock(&rdev->mutex); 2467414c70cbSLiam Girdwood return ret; 2468414c70cbSLiam Girdwood } 2469414c70cbSLiam Girdwood EXPORT_SYMBOL_GPL(regulator_set_optimum_mode); 2470414c70cbSLiam Girdwood 2471414c70cbSLiam Girdwood /** 2472414c70cbSLiam Girdwood * regulator_register_notifier - register regulator event notifier 2473414c70cbSLiam Girdwood * @regulator: regulator source 247469279fb9SMark Brown * @nb: notifier block 2475414c70cbSLiam Girdwood * 2476414c70cbSLiam Girdwood * Register notifier block to receive regulator events. 2477414c70cbSLiam Girdwood */ 2478414c70cbSLiam Girdwood int regulator_register_notifier(struct regulator *regulator, 2479414c70cbSLiam Girdwood struct notifier_block *nb) 2480414c70cbSLiam Girdwood { 2481414c70cbSLiam Girdwood return blocking_notifier_chain_register(®ulator->rdev->notifier, 2482414c70cbSLiam Girdwood nb); 2483414c70cbSLiam Girdwood } 2484414c70cbSLiam Girdwood EXPORT_SYMBOL_GPL(regulator_register_notifier); 2485414c70cbSLiam Girdwood 2486414c70cbSLiam Girdwood /** 2487414c70cbSLiam Girdwood * regulator_unregister_notifier - unregister regulator event notifier 2488414c70cbSLiam Girdwood * @regulator: regulator source 248969279fb9SMark Brown * @nb: notifier block 2490414c70cbSLiam Girdwood * 2491414c70cbSLiam Girdwood * Unregister regulator event notifier block. 2492414c70cbSLiam Girdwood */ 2493414c70cbSLiam Girdwood int regulator_unregister_notifier(struct regulator *regulator, 2494414c70cbSLiam Girdwood struct notifier_block *nb) 2495414c70cbSLiam Girdwood { 2496414c70cbSLiam Girdwood return blocking_notifier_chain_unregister(®ulator->rdev->notifier, 2497414c70cbSLiam Girdwood nb); 2498414c70cbSLiam Girdwood } 2499414c70cbSLiam Girdwood EXPORT_SYMBOL_GPL(regulator_unregister_notifier); 2500414c70cbSLiam Girdwood 2501b136fb44SJonathan Cameron /* notify regulator consumers and downstream regulator consumers. 2502b136fb44SJonathan Cameron * Note mutex must be held by caller. 2503b136fb44SJonathan Cameron */ 2504414c70cbSLiam Girdwood static void _notifier_call_chain(struct regulator_dev *rdev, 2505414c70cbSLiam Girdwood unsigned long event, void *data) 2506414c70cbSLiam Girdwood { 2507414c70cbSLiam Girdwood /* call rdev chain first */ 2508414c70cbSLiam Girdwood blocking_notifier_call_chain(&rdev->notifier, event, NULL); 2509414c70cbSLiam Girdwood } 2510414c70cbSLiam Girdwood 2511414c70cbSLiam Girdwood /** 2512414c70cbSLiam Girdwood * regulator_bulk_get - get multiple regulator consumers 2513414c70cbSLiam Girdwood * 2514414c70cbSLiam Girdwood * @dev: Device to supply 2515414c70cbSLiam Girdwood * @num_consumers: Number of consumers to register 2516414c70cbSLiam Girdwood * @consumers: Configuration of consumers; clients are stored here. 2517414c70cbSLiam Girdwood * 2518414c70cbSLiam Girdwood * @return 0 on success, an errno on failure. 2519414c70cbSLiam Girdwood * 2520414c70cbSLiam Girdwood * This helper function allows drivers to get several regulator 2521414c70cbSLiam Girdwood * consumers in one operation. If any of the regulators cannot be 2522414c70cbSLiam Girdwood * acquired then any regulators that were allocated will be freed 2523414c70cbSLiam Girdwood * before returning to the caller. 2524414c70cbSLiam Girdwood */ 2525414c70cbSLiam Girdwood int regulator_bulk_get(struct device *dev, int num_consumers, 2526414c70cbSLiam Girdwood struct regulator_bulk_data *consumers) 2527414c70cbSLiam Girdwood { 2528414c70cbSLiam Girdwood int i; 2529414c70cbSLiam Girdwood int ret; 2530414c70cbSLiam Girdwood 2531414c70cbSLiam Girdwood for (i = 0; i < num_consumers; i++) 2532414c70cbSLiam Girdwood consumers[i].consumer = NULL; 2533414c70cbSLiam Girdwood 2534414c70cbSLiam Girdwood for (i = 0; i < num_consumers; i++) { 2535414c70cbSLiam Girdwood consumers[i].consumer = regulator_get(dev, 2536414c70cbSLiam Girdwood consumers[i].supply); 2537414c70cbSLiam Girdwood if (IS_ERR(consumers[i].consumer)) { 2538414c70cbSLiam Girdwood ret = PTR_ERR(consumers[i].consumer); 25395b307627SMark Brown dev_err(dev, "Failed to get supply '%s': %d\n", 25405b307627SMark Brown consumers[i].supply, ret); 2541414c70cbSLiam Girdwood consumers[i].consumer = NULL; 2542414c70cbSLiam Girdwood goto err; 2543414c70cbSLiam Girdwood } 2544414c70cbSLiam Girdwood } 2545414c70cbSLiam Girdwood 2546414c70cbSLiam Girdwood return 0; 2547414c70cbSLiam Girdwood 2548414c70cbSLiam Girdwood err: 2549b29c7690SAxel Lin while (--i >= 0) 2550414c70cbSLiam Girdwood regulator_put(consumers[i].consumer); 2551414c70cbSLiam Girdwood 2552414c70cbSLiam Girdwood return ret; 2553414c70cbSLiam Girdwood } 2554414c70cbSLiam Girdwood EXPORT_SYMBOL_GPL(regulator_bulk_get); 2555414c70cbSLiam Girdwood 2556e6e74030SMark Brown /** 2557e6e74030SMark Brown * devm_regulator_bulk_get - managed get multiple regulator consumers 2558e6e74030SMark Brown * 2559e6e74030SMark Brown * @dev: Device to supply 2560e6e74030SMark Brown * @num_consumers: Number of consumers to register 2561e6e74030SMark Brown * @consumers: Configuration of consumers; clients are stored here. 2562e6e74030SMark Brown * 2563e6e74030SMark Brown * @return 0 on success, an errno on failure. 2564e6e74030SMark Brown * 2565e6e74030SMark Brown * This helper function allows drivers to get several regulator 2566e6e74030SMark Brown * consumers in one operation with management, the regulators will 2567e6e74030SMark Brown * automatically be freed when the device is unbound. If any of the 2568e6e74030SMark Brown * regulators cannot be acquired then any regulators that were 2569e6e74030SMark Brown * allocated will be freed before returning to the caller. 2570e6e74030SMark Brown */ 2571e6e74030SMark Brown int devm_regulator_bulk_get(struct device *dev, int num_consumers, 2572e6e74030SMark Brown struct regulator_bulk_data *consumers) 2573e6e74030SMark Brown { 2574e6e74030SMark Brown int i; 2575e6e74030SMark Brown int ret; 2576e6e74030SMark Brown 2577e6e74030SMark Brown for (i = 0; i < num_consumers; i++) 2578e6e74030SMark Brown consumers[i].consumer = NULL; 2579e6e74030SMark Brown 2580e6e74030SMark Brown for (i = 0; i < num_consumers; i++) { 2581e6e74030SMark Brown consumers[i].consumer = devm_regulator_get(dev, 2582e6e74030SMark Brown consumers[i].supply); 2583e6e74030SMark Brown if (IS_ERR(consumers[i].consumer)) { 2584e6e74030SMark Brown ret = PTR_ERR(consumers[i].consumer); 2585e6e74030SMark Brown dev_err(dev, "Failed to get supply '%s': %d\n", 2586e6e74030SMark Brown consumers[i].supply, ret); 2587e6e74030SMark Brown consumers[i].consumer = NULL; 2588e6e74030SMark Brown goto err; 2589e6e74030SMark Brown } 2590e6e74030SMark Brown } 2591e6e74030SMark Brown 2592e6e74030SMark Brown return 0; 2593e6e74030SMark Brown 2594e6e74030SMark Brown err: 2595e6e74030SMark Brown for (i = 0; i < num_consumers && consumers[i].consumer; i++) 2596e6e74030SMark Brown devm_regulator_put(consumers[i].consumer); 2597e6e74030SMark Brown 2598e6e74030SMark Brown return ret; 2599e6e74030SMark Brown } 2600e6e74030SMark Brown EXPORT_SYMBOL_GPL(devm_regulator_bulk_get); 2601e6e74030SMark Brown 2602f21e0e81SMark Brown static void regulator_bulk_enable_async(void *data, async_cookie_t cookie) 2603f21e0e81SMark Brown { 2604f21e0e81SMark Brown struct regulator_bulk_data *bulk = data; 2605f21e0e81SMark Brown 2606f21e0e81SMark Brown bulk->ret = regulator_enable(bulk->consumer); 2607f21e0e81SMark Brown } 2608f21e0e81SMark Brown 2609414c70cbSLiam Girdwood /** 2610414c70cbSLiam Girdwood * regulator_bulk_enable - enable multiple regulator consumers 2611414c70cbSLiam Girdwood * 2612414c70cbSLiam Girdwood * @num_consumers: Number of consumers 2613414c70cbSLiam Girdwood * @consumers: Consumer data; clients are stored here. 2614414c70cbSLiam Girdwood * @return 0 on success, an errno on failure 2615414c70cbSLiam Girdwood * 2616414c70cbSLiam Girdwood * This convenience API allows consumers to enable multiple regulator 2617414c70cbSLiam Girdwood * clients in a single API call. If any consumers cannot be enabled 2618414c70cbSLiam Girdwood * then any others that were enabled will be disabled again prior to 2619414c70cbSLiam Girdwood * return. 2620414c70cbSLiam Girdwood */ 2621414c70cbSLiam Girdwood int regulator_bulk_enable(int num_consumers, 2622414c70cbSLiam Girdwood struct regulator_bulk_data *consumers) 2623414c70cbSLiam Girdwood { 2624f21e0e81SMark Brown LIST_HEAD(async_domain); 2625414c70cbSLiam Girdwood int i; 2626f21e0e81SMark Brown int ret = 0; 2627414c70cbSLiam Girdwood 2628f21e0e81SMark Brown for (i = 0; i < num_consumers; i++) 2629f21e0e81SMark Brown async_schedule_domain(regulator_bulk_enable_async, 2630f21e0e81SMark Brown &consumers[i], &async_domain); 2631f21e0e81SMark Brown 2632f21e0e81SMark Brown async_synchronize_full_domain(&async_domain); 2633f21e0e81SMark Brown 2634f21e0e81SMark Brown /* If any consumer failed we need to unwind any that succeeded */ 2635414c70cbSLiam Girdwood for (i = 0; i < num_consumers; i++) { 2636f21e0e81SMark Brown if (consumers[i].ret != 0) { 2637f21e0e81SMark Brown ret = consumers[i].ret; 2638414c70cbSLiam Girdwood goto err; 2639414c70cbSLiam Girdwood } 2640f21e0e81SMark Brown } 2641414c70cbSLiam Girdwood 2642414c70cbSLiam Girdwood return 0; 2643414c70cbSLiam Girdwood 2644414c70cbSLiam Girdwood err: 2645b29c7690SAxel Lin pr_err("Failed to enable %s: %d\n", consumers[i].supply, ret); 2646b29c7690SAxel Lin while (--i >= 0) 2647414c70cbSLiam Girdwood regulator_disable(consumers[i].consumer); 2648414c70cbSLiam Girdwood 2649414c70cbSLiam Girdwood return ret; 2650414c70cbSLiam Girdwood } 2651414c70cbSLiam Girdwood EXPORT_SYMBOL_GPL(regulator_bulk_enable); 2652414c70cbSLiam Girdwood 2653414c70cbSLiam Girdwood /** 2654414c70cbSLiam Girdwood * regulator_bulk_disable - disable multiple regulator consumers 2655414c70cbSLiam Girdwood * 2656414c70cbSLiam Girdwood * @num_consumers: Number of consumers 2657414c70cbSLiam Girdwood * @consumers: Consumer data; clients are stored here. 2658414c70cbSLiam Girdwood * @return 0 on success, an errno on failure 2659414c70cbSLiam Girdwood * 2660414c70cbSLiam Girdwood * This convenience API allows consumers to disable multiple regulator 266149e22632SSylwester Nawrocki * clients in a single API call. If any consumers cannot be disabled 266249e22632SSylwester Nawrocki * then any others that were disabled will be enabled again prior to 2663414c70cbSLiam Girdwood * return. 2664414c70cbSLiam Girdwood */ 2665414c70cbSLiam Girdwood int regulator_bulk_disable(int num_consumers, 2666414c70cbSLiam Girdwood struct regulator_bulk_data *consumers) 2667414c70cbSLiam Girdwood { 2668414c70cbSLiam Girdwood int i; 2669414c70cbSLiam Girdwood int ret; 2670414c70cbSLiam Girdwood 267149e22632SSylwester Nawrocki for (i = num_consumers - 1; i >= 0; --i) { 2672414c70cbSLiam Girdwood ret = regulator_disable(consumers[i].consumer); 2673414c70cbSLiam Girdwood if (ret != 0) 2674414c70cbSLiam Girdwood goto err; 2675414c70cbSLiam Girdwood } 2676414c70cbSLiam Girdwood 2677414c70cbSLiam Girdwood return 0; 2678414c70cbSLiam Girdwood 2679414c70cbSLiam Girdwood err: 26805da84fd9SJoe Perches pr_err("Failed to disable %s: %d\n", consumers[i].supply, ret); 268149e22632SSylwester Nawrocki for (++i; i < num_consumers; ++i) 2682414c70cbSLiam Girdwood regulator_enable(consumers[i].consumer); 2683414c70cbSLiam Girdwood 2684414c70cbSLiam Girdwood return ret; 2685414c70cbSLiam Girdwood } 2686414c70cbSLiam Girdwood EXPORT_SYMBOL_GPL(regulator_bulk_disable); 2687414c70cbSLiam Girdwood 2688414c70cbSLiam Girdwood /** 2689e1de2f42SDonggeun Kim * regulator_bulk_force_disable - force disable multiple regulator consumers 2690e1de2f42SDonggeun Kim * 2691e1de2f42SDonggeun Kim * @num_consumers: Number of consumers 2692e1de2f42SDonggeun Kim * @consumers: Consumer data; clients are stored here. 2693e1de2f42SDonggeun Kim * @return 0 on success, an errno on failure 2694e1de2f42SDonggeun Kim * 2695e1de2f42SDonggeun Kim * This convenience API allows consumers to forcibly disable multiple regulator 2696e1de2f42SDonggeun Kim * clients in a single API call. 2697e1de2f42SDonggeun Kim * NOTE: This should be used for situations when device damage will 2698e1de2f42SDonggeun Kim * likely occur if the regulators are not disabled (e.g. over temp). 2699e1de2f42SDonggeun Kim * Although regulator_force_disable function call for some consumers can 2700e1de2f42SDonggeun Kim * return error numbers, the function is called for all consumers. 2701e1de2f42SDonggeun Kim */ 2702e1de2f42SDonggeun Kim int regulator_bulk_force_disable(int num_consumers, 2703e1de2f42SDonggeun Kim struct regulator_bulk_data *consumers) 2704e1de2f42SDonggeun Kim { 2705e1de2f42SDonggeun Kim int i; 2706e1de2f42SDonggeun Kim int ret; 2707e1de2f42SDonggeun Kim 2708e1de2f42SDonggeun Kim for (i = 0; i < num_consumers; i++) 2709e1de2f42SDonggeun Kim consumers[i].ret = 2710e1de2f42SDonggeun Kim regulator_force_disable(consumers[i].consumer); 2711e1de2f42SDonggeun Kim 2712e1de2f42SDonggeun Kim for (i = 0; i < num_consumers; i++) { 2713e1de2f42SDonggeun Kim if (consumers[i].ret != 0) { 2714e1de2f42SDonggeun Kim ret = consumers[i].ret; 2715e1de2f42SDonggeun Kim goto out; 2716e1de2f42SDonggeun Kim } 2717e1de2f42SDonggeun Kim } 2718e1de2f42SDonggeun Kim 2719e1de2f42SDonggeun Kim return 0; 2720e1de2f42SDonggeun Kim out: 2721e1de2f42SDonggeun Kim return ret; 2722e1de2f42SDonggeun Kim } 2723e1de2f42SDonggeun Kim EXPORT_SYMBOL_GPL(regulator_bulk_force_disable); 2724e1de2f42SDonggeun Kim 2725e1de2f42SDonggeun Kim /** 2726414c70cbSLiam Girdwood * regulator_bulk_free - free multiple regulator consumers 2727414c70cbSLiam Girdwood * 2728414c70cbSLiam Girdwood * @num_consumers: Number of consumers 2729414c70cbSLiam Girdwood * @consumers: Consumer data; clients are stored here. 2730414c70cbSLiam Girdwood * 2731414c70cbSLiam Girdwood * This convenience API allows consumers to free multiple regulator 2732414c70cbSLiam Girdwood * clients in a single API call. 2733414c70cbSLiam Girdwood */ 2734414c70cbSLiam Girdwood void regulator_bulk_free(int num_consumers, 2735414c70cbSLiam Girdwood struct regulator_bulk_data *consumers) 2736414c70cbSLiam Girdwood { 2737414c70cbSLiam Girdwood int i; 2738414c70cbSLiam Girdwood 2739414c70cbSLiam Girdwood for (i = 0; i < num_consumers; i++) { 2740414c70cbSLiam Girdwood regulator_put(consumers[i].consumer); 2741414c70cbSLiam Girdwood consumers[i].consumer = NULL; 2742414c70cbSLiam Girdwood } 2743414c70cbSLiam Girdwood } 2744414c70cbSLiam Girdwood EXPORT_SYMBOL_GPL(regulator_bulk_free); 2745414c70cbSLiam Girdwood 2746414c70cbSLiam Girdwood /** 2747414c70cbSLiam Girdwood * regulator_notifier_call_chain - call regulator event notifier 274869279fb9SMark Brown * @rdev: regulator source 2749414c70cbSLiam Girdwood * @event: notifier block 275069279fb9SMark Brown * @data: callback-specific data. 2751414c70cbSLiam Girdwood * 2752414c70cbSLiam Girdwood * Called by regulator drivers to notify clients a regulator event has 2753414c70cbSLiam Girdwood * occurred. We also notify regulator clients downstream. 2754b136fb44SJonathan Cameron * Note lock must be held by caller. 2755414c70cbSLiam Girdwood */ 2756414c70cbSLiam Girdwood int regulator_notifier_call_chain(struct regulator_dev *rdev, 2757414c70cbSLiam Girdwood unsigned long event, void *data) 2758414c70cbSLiam Girdwood { 2759414c70cbSLiam Girdwood _notifier_call_chain(rdev, event, data); 2760414c70cbSLiam Girdwood return NOTIFY_DONE; 2761414c70cbSLiam Girdwood 2762414c70cbSLiam Girdwood } 2763414c70cbSLiam Girdwood EXPORT_SYMBOL_GPL(regulator_notifier_call_chain); 2764414c70cbSLiam Girdwood 2765be721979SMark Brown /** 2766be721979SMark Brown * regulator_mode_to_status - convert a regulator mode into a status 2767be721979SMark Brown * 2768be721979SMark Brown * @mode: Mode to convert 2769be721979SMark Brown * 2770be721979SMark Brown * Convert a regulator mode into a status. 2771be721979SMark Brown */ 2772be721979SMark Brown int regulator_mode_to_status(unsigned int mode) 2773be721979SMark Brown { 2774be721979SMark Brown switch (mode) { 2775be721979SMark Brown case REGULATOR_MODE_FAST: 2776be721979SMark Brown return REGULATOR_STATUS_FAST; 2777be721979SMark Brown case REGULATOR_MODE_NORMAL: 2778be721979SMark Brown return REGULATOR_STATUS_NORMAL; 2779be721979SMark Brown case REGULATOR_MODE_IDLE: 2780be721979SMark Brown return REGULATOR_STATUS_IDLE; 2781be721979SMark Brown case REGULATOR_STATUS_STANDBY: 2782be721979SMark Brown return REGULATOR_STATUS_STANDBY; 2783be721979SMark Brown default: 2784be721979SMark Brown return 0; 2785be721979SMark Brown } 2786be721979SMark Brown } 2787be721979SMark Brown EXPORT_SYMBOL_GPL(regulator_mode_to_status); 2788be721979SMark Brown 27897ad68e2fSDavid Brownell /* 27907ad68e2fSDavid Brownell * To avoid cluttering sysfs (and memory) with useless state, only 27917ad68e2fSDavid Brownell * create attributes that can be meaningfully displayed. 27927ad68e2fSDavid Brownell */ 27937ad68e2fSDavid Brownell static int add_regulator_attributes(struct regulator_dev *rdev) 27947ad68e2fSDavid Brownell { 27957ad68e2fSDavid Brownell struct device *dev = &rdev->dev; 27967ad68e2fSDavid Brownell struct regulator_ops *ops = rdev->desc->ops; 27977ad68e2fSDavid Brownell int status = 0; 27987ad68e2fSDavid Brownell 27997ad68e2fSDavid Brownell /* some attributes need specific methods to be displayed */ 28004c78899bSMark Brown if ((ops->get_voltage && ops->get_voltage(rdev) >= 0) || 28014c78899bSMark Brown (ops->get_voltage_sel && ops->get_voltage_sel(rdev) >= 0)) { 28027ad68e2fSDavid Brownell status = device_create_file(dev, &dev_attr_microvolts); 28037ad68e2fSDavid Brownell if (status < 0) 28047ad68e2fSDavid Brownell return status; 28057ad68e2fSDavid Brownell } 28067ad68e2fSDavid Brownell if (ops->get_current_limit) { 28077ad68e2fSDavid Brownell status = device_create_file(dev, &dev_attr_microamps); 28087ad68e2fSDavid Brownell if (status < 0) 28097ad68e2fSDavid Brownell return status; 28107ad68e2fSDavid Brownell } 28117ad68e2fSDavid Brownell if (ops->get_mode) { 28127ad68e2fSDavid Brownell status = device_create_file(dev, &dev_attr_opmode); 28137ad68e2fSDavid Brownell if (status < 0) 28147ad68e2fSDavid Brownell return status; 28157ad68e2fSDavid Brownell } 28167ad68e2fSDavid Brownell if (ops->is_enabled) { 28177ad68e2fSDavid Brownell status = device_create_file(dev, &dev_attr_state); 28187ad68e2fSDavid Brownell if (status < 0) 28197ad68e2fSDavid Brownell return status; 28207ad68e2fSDavid Brownell } 2821853116a1SDavid Brownell if (ops->get_status) { 2822853116a1SDavid Brownell status = device_create_file(dev, &dev_attr_status); 2823853116a1SDavid Brownell if (status < 0) 2824853116a1SDavid Brownell return status; 2825853116a1SDavid Brownell } 28267ad68e2fSDavid Brownell 28277ad68e2fSDavid Brownell /* some attributes are type-specific */ 28287ad68e2fSDavid Brownell if (rdev->desc->type == REGULATOR_CURRENT) { 28297ad68e2fSDavid Brownell status = device_create_file(dev, &dev_attr_requested_microamps); 28307ad68e2fSDavid Brownell if (status < 0) 28317ad68e2fSDavid Brownell return status; 28327ad68e2fSDavid Brownell } 28337ad68e2fSDavid Brownell 28347ad68e2fSDavid Brownell /* all the other attributes exist to support constraints; 28357ad68e2fSDavid Brownell * don't show them if there are no constraints, or if the 28367ad68e2fSDavid Brownell * relevant supporting methods are missing. 28377ad68e2fSDavid Brownell */ 28387ad68e2fSDavid Brownell if (!rdev->constraints) 28397ad68e2fSDavid Brownell return status; 28407ad68e2fSDavid Brownell 28417ad68e2fSDavid Brownell /* constraints need specific supporting methods */ 2842e8eef82bSMark Brown if (ops->set_voltage || ops->set_voltage_sel) { 28437ad68e2fSDavid Brownell status = device_create_file(dev, &dev_attr_min_microvolts); 28447ad68e2fSDavid Brownell if (status < 0) 28457ad68e2fSDavid Brownell return status; 28467ad68e2fSDavid Brownell status = device_create_file(dev, &dev_attr_max_microvolts); 28477ad68e2fSDavid Brownell if (status < 0) 28487ad68e2fSDavid Brownell return status; 28497ad68e2fSDavid Brownell } 28507ad68e2fSDavid Brownell if (ops->set_current_limit) { 28517ad68e2fSDavid Brownell status = device_create_file(dev, &dev_attr_min_microamps); 28527ad68e2fSDavid Brownell if (status < 0) 28537ad68e2fSDavid Brownell return status; 28547ad68e2fSDavid Brownell status = device_create_file(dev, &dev_attr_max_microamps); 28557ad68e2fSDavid Brownell if (status < 0) 28567ad68e2fSDavid Brownell return status; 28577ad68e2fSDavid Brownell } 28587ad68e2fSDavid Brownell 28597ad68e2fSDavid Brownell /* suspend mode constraints need multiple supporting methods */ 28607ad68e2fSDavid Brownell if (!(ops->set_suspend_enable && ops->set_suspend_disable)) 28617ad68e2fSDavid Brownell return status; 28627ad68e2fSDavid Brownell 28637ad68e2fSDavid Brownell status = device_create_file(dev, &dev_attr_suspend_standby_state); 28647ad68e2fSDavid Brownell if (status < 0) 28657ad68e2fSDavid Brownell return status; 28667ad68e2fSDavid Brownell status = device_create_file(dev, &dev_attr_suspend_mem_state); 28677ad68e2fSDavid Brownell if (status < 0) 28687ad68e2fSDavid Brownell return status; 28697ad68e2fSDavid Brownell status = device_create_file(dev, &dev_attr_suspend_disk_state); 28707ad68e2fSDavid Brownell if (status < 0) 28717ad68e2fSDavid Brownell return status; 28727ad68e2fSDavid Brownell 28737ad68e2fSDavid Brownell if (ops->set_suspend_voltage) { 28747ad68e2fSDavid Brownell status = device_create_file(dev, 28757ad68e2fSDavid Brownell &dev_attr_suspend_standby_microvolts); 28767ad68e2fSDavid Brownell if (status < 0) 28777ad68e2fSDavid Brownell return status; 28787ad68e2fSDavid Brownell status = device_create_file(dev, 28797ad68e2fSDavid Brownell &dev_attr_suspend_mem_microvolts); 28807ad68e2fSDavid Brownell if (status < 0) 28817ad68e2fSDavid Brownell return status; 28827ad68e2fSDavid Brownell status = device_create_file(dev, 28837ad68e2fSDavid Brownell &dev_attr_suspend_disk_microvolts); 28847ad68e2fSDavid Brownell if (status < 0) 28857ad68e2fSDavid Brownell return status; 28867ad68e2fSDavid Brownell } 28877ad68e2fSDavid Brownell 28887ad68e2fSDavid Brownell if (ops->set_suspend_mode) { 28897ad68e2fSDavid Brownell status = device_create_file(dev, 28907ad68e2fSDavid Brownell &dev_attr_suspend_standby_mode); 28917ad68e2fSDavid Brownell if (status < 0) 28927ad68e2fSDavid Brownell return status; 28937ad68e2fSDavid Brownell status = device_create_file(dev, 28947ad68e2fSDavid Brownell &dev_attr_suspend_mem_mode); 28957ad68e2fSDavid Brownell if (status < 0) 28967ad68e2fSDavid Brownell return status; 28977ad68e2fSDavid Brownell status = device_create_file(dev, 28987ad68e2fSDavid Brownell &dev_attr_suspend_disk_mode); 28997ad68e2fSDavid Brownell if (status < 0) 29007ad68e2fSDavid Brownell return status; 29017ad68e2fSDavid Brownell } 29027ad68e2fSDavid Brownell 29037ad68e2fSDavid Brownell return status; 29047ad68e2fSDavid Brownell } 29057ad68e2fSDavid Brownell 29061130e5b3SMark Brown static void rdev_init_debugfs(struct regulator_dev *rdev) 29071130e5b3SMark Brown { 29081130e5b3SMark Brown rdev->debugfs = debugfs_create_dir(rdev_get_name(rdev), debugfs_root); 290924751434SStephen Boyd if (!rdev->debugfs) { 29101130e5b3SMark Brown rdev_warn(rdev, "Failed to create debugfs directory\n"); 29111130e5b3SMark Brown return; 29121130e5b3SMark Brown } 29131130e5b3SMark Brown 29141130e5b3SMark Brown debugfs_create_u32("use_count", 0444, rdev->debugfs, 29151130e5b3SMark Brown &rdev->use_count); 29161130e5b3SMark Brown debugfs_create_u32("open_count", 0444, rdev->debugfs, 29171130e5b3SMark Brown &rdev->open_count); 29181130e5b3SMark Brown } 29191130e5b3SMark Brown 2920414c70cbSLiam Girdwood /** 2921414c70cbSLiam Girdwood * regulator_register - register regulator 292269279fb9SMark Brown * @regulator_desc: regulator to register 2923c172708dSMark Brown * @config: runtime configuration for regulator 2924414c70cbSLiam Girdwood * 2925414c70cbSLiam Girdwood * Called by regulator drivers to register a regulator. 2926414c70cbSLiam Girdwood * Returns 0 on success. 2927414c70cbSLiam Girdwood */ 292865f26846SMark Brown struct regulator_dev * 292965f26846SMark Brown regulator_register(const struct regulator_desc *regulator_desc, 2930c172708dSMark Brown const struct regulator_config *config) 2931414c70cbSLiam Girdwood { 29329a8f5e07SMark Brown const struct regulation_constraints *constraints = NULL; 2933c172708dSMark Brown const struct regulator_init_data *init_data; 2934414c70cbSLiam Girdwood static atomic_t regulator_no = ATOMIC_INIT(0); 2935414c70cbSLiam Girdwood struct regulator_dev *rdev; 293632c8fad4SMark Brown struct device *dev; 2937a5766f11SLiam Girdwood int ret, i; 293869511a45SRajendra Nayak const char *supply = NULL; 2939414c70cbSLiam Girdwood 2940c172708dSMark Brown if (regulator_desc == NULL || config == NULL) 2941414c70cbSLiam Girdwood return ERR_PTR(-EINVAL); 2942414c70cbSLiam Girdwood 294332c8fad4SMark Brown dev = config->dev; 294432c8fad4SMark Brown 2945414c70cbSLiam Girdwood if (regulator_desc->name == NULL || regulator_desc->ops == NULL) 2946414c70cbSLiam Girdwood return ERR_PTR(-EINVAL); 2947414c70cbSLiam Girdwood 2948cd78dfc6SDiego Liziero if (regulator_desc->type != REGULATOR_VOLTAGE && 2949cd78dfc6SDiego Liziero regulator_desc->type != REGULATOR_CURRENT) 2950414c70cbSLiam Girdwood return ERR_PTR(-EINVAL); 2951414c70cbSLiam Girdwood 2952476c2d83SMark Brown /* Only one of each should be implemented */ 2953476c2d83SMark Brown WARN_ON(regulator_desc->ops->get_voltage && 2954476c2d83SMark Brown regulator_desc->ops->get_voltage_sel); 2955e8eef82bSMark Brown WARN_ON(regulator_desc->ops->set_voltage && 2956e8eef82bSMark Brown regulator_desc->ops->set_voltage_sel); 2957476c2d83SMark Brown 2958476c2d83SMark Brown /* If we're using selectors we must implement list_voltage. */ 2959476c2d83SMark Brown if (regulator_desc->ops->get_voltage_sel && 2960476c2d83SMark Brown !regulator_desc->ops->list_voltage) { 2961476c2d83SMark Brown return ERR_PTR(-EINVAL); 2962476c2d83SMark Brown } 2963e8eef82bSMark Brown if (regulator_desc->ops->set_voltage_sel && 2964e8eef82bSMark Brown !regulator_desc->ops->list_voltage) { 2965e8eef82bSMark Brown return ERR_PTR(-EINVAL); 2966e8eef82bSMark Brown } 2967476c2d83SMark Brown 2968c172708dSMark Brown init_data = config->init_data; 2969c172708dSMark Brown 2970414c70cbSLiam Girdwood rdev = kzalloc(sizeof(struct regulator_dev), GFP_KERNEL); 2971414c70cbSLiam Girdwood if (rdev == NULL) 2972414c70cbSLiam Girdwood return ERR_PTR(-ENOMEM); 2973414c70cbSLiam Girdwood 2974414c70cbSLiam Girdwood mutex_lock(®ulator_list_mutex); 2975414c70cbSLiam Girdwood 2976414c70cbSLiam Girdwood mutex_init(&rdev->mutex); 2977c172708dSMark Brown rdev->reg_data = config->driver_data; 2978414c70cbSLiam Girdwood rdev->owner = regulator_desc->owner; 2979414c70cbSLiam Girdwood rdev->desc = regulator_desc; 298065b19ce6SMark Brown rdev->regmap = config->regmap; 2981414c70cbSLiam Girdwood INIT_LIST_HEAD(&rdev->consumer_list); 2982414c70cbSLiam Girdwood INIT_LIST_HEAD(&rdev->list); 2983414c70cbSLiam Girdwood BLOCKING_INIT_NOTIFIER_HEAD(&rdev->notifier); 2984da07ecd9SMark Brown INIT_DELAYED_WORK(&rdev->disable_work, regulator_disable_work); 2985414c70cbSLiam Girdwood 2986a5766f11SLiam Girdwood /* preform any regulator specific init */ 29879a8f5e07SMark Brown if (init_data && init_data->regulator_init) { 2988a5766f11SLiam Girdwood ret = init_data->regulator_init(rdev->reg_data); 29894fca9545SDavid Brownell if (ret < 0) 29904fca9545SDavid Brownell goto clean; 2991a5766f11SLiam Girdwood } 2992a5766f11SLiam Girdwood 2993a5766f11SLiam Girdwood /* register with sysfs */ 2994a5766f11SLiam Girdwood rdev->dev.class = ®ulator_class; 2995c172708dSMark Brown rdev->dev.of_node = config->of_node; 2996a5766f11SLiam Girdwood rdev->dev.parent = dev; 2997812460a9SKay Sievers dev_set_name(&rdev->dev, "regulator.%d", 2998812460a9SKay Sievers atomic_inc_return(®ulator_no) - 1); 2999a5766f11SLiam Girdwood ret = device_register(&rdev->dev); 3000ad7725cbSVasiliy Kulikov if (ret != 0) { 3001ad7725cbSVasiliy Kulikov put_device(&rdev->dev); 30024fca9545SDavid Brownell goto clean; 3003ad7725cbSVasiliy Kulikov } 3004a5766f11SLiam Girdwood 3005a5766f11SLiam Girdwood dev_set_drvdata(&rdev->dev, rdev); 3006a5766f11SLiam Girdwood 300774f544c1SMike Rapoport /* set regulator constraints */ 30089a8f5e07SMark Brown if (init_data) 30099a8f5e07SMark Brown constraints = &init_data->constraints; 30109a8f5e07SMark Brown 30119a8f5e07SMark Brown ret = set_machine_constraints(rdev, constraints); 301274f544c1SMike Rapoport if (ret < 0) 301374f544c1SMike Rapoport goto scrub; 301474f544c1SMike Rapoport 30157ad68e2fSDavid Brownell /* add attributes supported by this regulator */ 30167ad68e2fSDavid Brownell ret = add_regulator_attributes(rdev); 30177ad68e2fSDavid Brownell if (ret < 0) 30187ad68e2fSDavid Brownell goto scrub; 30197ad68e2fSDavid Brownell 30209a8f5e07SMark Brown if (init_data && init_data->supply_regulator) 302169511a45SRajendra Nayak supply = init_data->supply_regulator; 302269511a45SRajendra Nayak else if (regulator_desc->supply_name) 302369511a45SRajendra Nayak supply = regulator_desc->supply_name; 302469511a45SRajendra Nayak 302569511a45SRajendra Nayak if (supply) { 30260178f3e2SMark Brown struct regulator_dev *r; 30270178f3e2SMark Brown 302869511a45SRajendra Nayak r = regulator_dev_lookup(dev, supply); 30290178f3e2SMark Brown 303069511a45SRajendra Nayak if (!r) { 303169511a45SRajendra Nayak dev_err(dev, "Failed to find supply %s\n", supply); 303204bf3011SMark Brown ret = -EPROBE_DEFER; 30330178f3e2SMark Brown goto scrub; 30340178f3e2SMark Brown } 30350178f3e2SMark Brown 30360178f3e2SMark Brown ret = set_supply(rdev, r); 30370178f3e2SMark Brown if (ret < 0) 30380178f3e2SMark Brown goto scrub; 3039b2296bd4SLaxman Dewangan 3040b2296bd4SLaxman Dewangan /* Enable supply if rail is enabled */ 3041b2296bd4SLaxman Dewangan if (rdev->desc->ops->is_enabled && 3042b2296bd4SLaxman Dewangan rdev->desc->ops->is_enabled(rdev)) { 3043b2296bd4SLaxman Dewangan ret = regulator_enable(rdev->supply); 3044b2296bd4SLaxman Dewangan if (ret < 0) 3045b2296bd4SLaxman Dewangan goto scrub; 3046b2296bd4SLaxman Dewangan } 30470178f3e2SMark Brown } 30480178f3e2SMark Brown 3049a5766f11SLiam Girdwood /* add consumers devices */ 30509a8f5e07SMark Brown if (init_data) { 3051a5766f11SLiam Girdwood for (i = 0; i < init_data->num_consumer_supplies; i++) { 3052a5766f11SLiam Girdwood ret = set_consumer_device_supply(rdev, 305340f9244fSMark Brown init_data->consumer_supplies[i].dev_name, 3054a5766f11SLiam Girdwood init_data->consumer_supplies[i].supply); 305523c2f041SMark Brown if (ret < 0) { 305623c2f041SMark Brown dev_err(dev, "Failed to set supply %s\n", 305723c2f041SMark Brown init_data->consumer_supplies[i].supply); 3058d4033b54SJani Nikula goto unset_supplies; 3059a5766f11SLiam Girdwood } 306023c2f041SMark Brown } 30619a8f5e07SMark Brown } 3062a5766f11SLiam Girdwood 3063a5766f11SLiam Girdwood list_add(&rdev->list, ®ulator_list); 30641130e5b3SMark Brown 30651130e5b3SMark Brown rdev_init_debugfs(rdev); 3066a5766f11SLiam Girdwood out: 3067414c70cbSLiam Girdwood mutex_unlock(®ulator_list_mutex); 3068414c70cbSLiam Girdwood return rdev; 30694fca9545SDavid Brownell 3070d4033b54SJani Nikula unset_supplies: 3071d4033b54SJani Nikula unset_regulator_supplies(rdev); 3072d4033b54SJani Nikula 30734fca9545SDavid Brownell scrub: 30741a6958e7SAxel Lin kfree(rdev->constraints); 30754fca9545SDavid Brownell device_unregister(&rdev->dev); 307653032dafSPaul Walmsley /* device core frees rdev */ 307753032dafSPaul Walmsley rdev = ERR_PTR(ret); 307853032dafSPaul Walmsley goto out; 307953032dafSPaul Walmsley 30804fca9545SDavid Brownell clean: 30814fca9545SDavid Brownell kfree(rdev); 30824fca9545SDavid Brownell rdev = ERR_PTR(ret); 30834fca9545SDavid Brownell goto out; 3084414c70cbSLiam Girdwood } 3085414c70cbSLiam Girdwood EXPORT_SYMBOL_GPL(regulator_register); 3086414c70cbSLiam Girdwood 3087414c70cbSLiam Girdwood /** 3088414c70cbSLiam Girdwood * regulator_unregister - unregister regulator 308969279fb9SMark Brown * @rdev: regulator to unregister 3090414c70cbSLiam Girdwood * 3091414c70cbSLiam Girdwood * Called by regulator drivers to unregister a regulator. 3092414c70cbSLiam Girdwood */ 3093414c70cbSLiam Girdwood void regulator_unregister(struct regulator_dev *rdev) 3094414c70cbSLiam Girdwood { 3095414c70cbSLiam Girdwood if (rdev == NULL) 3096414c70cbSLiam Girdwood return; 3097414c70cbSLiam Girdwood 3098e032b376SMark Brown if (rdev->supply) 3099e032b376SMark Brown regulator_put(rdev->supply); 3100414c70cbSLiam Girdwood mutex_lock(®ulator_list_mutex); 31011130e5b3SMark Brown debugfs_remove_recursive(rdev->debugfs); 3102da07ecd9SMark Brown flush_work_sync(&rdev->disable_work.work); 31036bf87d17SMark Brown WARN_ON(rdev->open_count); 31040f1d747bSMike Rapoport unset_regulator_supplies(rdev); 3105414c70cbSLiam Girdwood list_del(&rdev->list); 3106f8c12fe3SMark Brown kfree(rdev->constraints); 310758fb5cf5SLothar Waßmann device_unregister(&rdev->dev); 3108414c70cbSLiam Girdwood mutex_unlock(®ulator_list_mutex); 3109414c70cbSLiam Girdwood } 3110414c70cbSLiam Girdwood EXPORT_SYMBOL_GPL(regulator_unregister); 3111414c70cbSLiam Girdwood 3112414c70cbSLiam Girdwood /** 3113cf7bbcdfSMark Brown * regulator_suspend_prepare - prepare regulators for system wide suspend 3114414c70cbSLiam Girdwood * @state: system suspend state 3115414c70cbSLiam Girdwood * 3116414c70cbSLiam Girdwood * Configure each regulator with it's suspend operating parameters for state. 3117414c70cbSLiam Girdwood * This will usually be called by machine suspend code prior to supending. 3118414c70cbSLiam Girdwood */ 3119414c70cbSLiam Girdwood int regulator_suspend_prepare(suspend_state_t state) 3120414c70cbSLiam Girdwood { 3121414c70cbSLiam Girdwood struct regulator_dev *rdev; 3122414c70cbSLiam Girdwood int ret = 0; 3123414c70cbSLiam Girdwood 3124414c70cbSLiam Girdwood /* ON is handled by regulator active state */ 3125414c70cbSLiam Girdwood if (state == PM_SUSPEND_ON) 3126414c70cbSLiam Girdwood return -EINVAL; 3127414c70cbSLiam Girdwood 3128414c70cbSLiam Girdwood mutex_lock(®ulator_list_mutex); 3129414c70cbSLiam Girdwood list_for_each_entry(rdev, ®ulator_list, list) { 3130414c70cbSLiam Girdwood 3131414c70cbSLiam Girdwood mutex_lock(&rdev->mutex); 3132414c70cbSLiam Girdwood ret = suspend_prepare(rdev, state); 3133414c70cbSLiam Girdwood mutex_unlock(&rdev->mutex); 3134414c70cbSLiam Girdwood 3135414c70cbSLiam Girdwood if (ret < 0) { 31365da84fd9SJoe Perches rdev_err(rdev, "failed to prepare\n"); 3137414c70cbSLiam Girdwood goto out; 3138414c70cbSLiam Girdwood } 3139414c70cbSLiam Girdwood } 3140414c70cbSLiam Girdwood out: 3141414c70cbSLiam Girdwood mutex_unlock(®ulator_list_mutex); 3142414c70cbSLiam Girdwood return ret; 3143414c70cbSLiam Girdwood } 3144414c70cbSLiam Girdwood EXPORT_SYMBOL_GPL(regulator_suspend_prepare); 3145414c70cbSLiam Girdwood 3146414c70cbSLiam Girdwood /** 31477a32b589SMyungJoo Ham * regulator_suspend_finish - resume regulators from system wide suspend 31487a32b589SMyungJoo Ham * 31497a32b589SMyungJoo Ham * Turn on regulators that might be turned off by regulator_suspend_prepare 31507a32b589SMyungJoo Ham * and that should be turned on according to the regulators properties. 31517a32b589SMyungJoo Ham */ 31527a32b589SMyungJoo Ham int regulator_suspend_finish(void) 31537a32b589SMyungJoo Ham { 31547a32b589SMyungJoo Ham struct regulator_dev *rdev; 31557a32b589SMyungJoo Ham int ret = 0, error; 31567a32b589SMyungJoo Ham 31577a32b589SMyungJoo Ham mutex_lock(®ulator_list_mutex); 31587a32b589SMyungJoo Ham list_for_each_entry(rdev, ®ulator_list, list) { 31597a32b589SMyungJoo Ham struct regulator_ops *ops = rdev->desc->ops; 31607a32b589SMyungJoo Ham 31617a32b589SMyungJoo Ham mutex_lock(&rdev->mutex); 31627a32b589SMyungJoo Ham if ((rdev->use_count > 0 || rdev->constraints->always_on) && 31637a32b589SMyungJoo Ham ops->enable) { 31647a32b589SMyungJoo Ham error = ops->enable(rdev); 31657a32b589SMyungJoo Ham if (error) 31667a32b589SMyungJoo Ham ret = error; 31677a32b589SMyungJoo Ham } else { 31687a32b589SMyungJoo Ham if (!has_full_constraints) 31697a32b589SMyungJoo Ham goto unlock; 31707a32b589SMyungJoo Ham if (!ops->disable) 31717a32b589SMyungJoo Ham goto unlock; 31727a32b589SMyungJoo Ham if (ops->is_enabled && !ops->is_enabled(rdev)) 31737a32b589SMyungJoo Ham goto unlock; 31747a32b589SMyungJoo Ham 31757a32b589SMyungJoo Ham error = ops->disable(rdev); 31767a32b589SMyungJoo Ham if (error) 31777a32b589SMyungJoo Ham ret = error; 31787a32b589SMyungJoo Ham } 31797a32b589SMyungJoo Ham unlock: 31807a32b589SMyungJoo Ham mutex_unlock(&rdev->mutex); 31817a32b589SMyungJoo Ham } 31827a32b589SMyungJoo Ham mutex_unlock(®ulator_list_mutex); 31837a32b589SMyungJoo Ham return ret; 31847a32b589SMyungJoo Ham } 31857a32b589SMyungJoo Ham EXPORT_SYMBOL_GPL(regulator_suspend_finish); 31867a32b589SMyungJoo Ham 31877a32b589SMyungJoo Ham /** 3188ca725561SMark Brown * regulator_has_full_constraints - the system has fully specified constraints 3189ca725561SMark Brown * 3190ca725561SMark Brown * Calling this function will cause the regulator API to disable all 3191ca725561SMark Brown * regulators which have a zero use count and don't have an always_on 3192ca725561SMark Brown * constraint in a late_initcall. 3193ca725561SMark Brown * 3194ca725561SMark Brown * The intention is that this will become the default behaviour in a 3195ca725561SMark Brown * future kernel release so users are encouraged to use this facility 3196ca725561SMark Brown * now. 3197ca725561SMark Brown */ 3198ca725561SMark Brown void regulator_has_full_constraints(void) 3199ca725561SMark Brown { 3200ca725561SMark Brown has_full_constraints = 1; 3201ca725561SMark Brown } 3202ca725561SMark Brown EXPORT_SYMBOL_GPL(regulator_has_full_constraints); 3203ca725561SMark Brown 3204ca725561SMark Brown /** 3205688fe99aSMark Brown * regulator_use_dummy_regulator - Provide a dummy regulator when none is found 3206688fe99aSMark Brown * 3207688fe99aSMark Brown * Calling this function will cause the regulator API to provide a 3208688fe99aSMark Brown * dummy regulator to consumers if no physical regulator is found, 3209688fe99aSMark Brown * allowing most consumers to proceed as though a regulator were 3210688fe99aSMark Brown * configured. This allows systems such as those with software 3211688fe99aSMark Brown * controllable regulators for the CPU core only to be brought up more 3212688fe99aSMark Brown * readily. 3213688fe99aSMark Brown */ 3214688fe99aSMark Brown void regulator_use_dummy_regulator(void) 3215688fe99aSMark Brown { 3216688fe99aSMark Brown board_wants_dummy_regulator = true; 3217688fe99aSMark Brown } 3218688fe99aSMark Brown EXPORT_SYMBOL_GPL(regulator_use_dummy_regulator); 3219688fe99aSMark Brown 3220688fe99aSMark Brown /** 3221414c70cbSLiam Girdwood * rdev_get_drvdata - get rdev regulator driver data 322269279fb9SMark Brown * @rdev: regulator 3223414c70cbSLiam Girdwood * 3224414c70cbSLiam Girdwood * Get rdev regulator driver private data. This call can be used in the 3225414c70cbSLiam Girdwood * regulator driver context. 3226414c70cbSLiam Girdwood */ 3227414c70cbSLiam Girdwood void *rdev_get_drvdata(struct regulator_dev *rdev) 3228414c70cbSLiam Girdwood { 3229414c70cbSLiam Girdwood return rdev->reg_data; 3230414c70cbSLiam Girdwood } 3231414c70cbSLiam Girdwood EXPORT_SYMBOL_GPL(rdev_get_drvdata); 3232414c70cbSLiam Girdwood 3233414c70cbSLiam Girdwood /** 3234414c70cbSLiam Girdwood * regulator_get_drvdata - get regulator driver data 3235414c70cbSLiam Girdwood * @regulator: regulator 3236414c70cbSLiam Girdwood * 3237414c70cbSLiam Girdwood * Get regulator driver private data. This call can be used in the consumer 3238414c70cbSLiam Girdwood * driver context when non API regulator specific functions need to be called. 3239414c70cbSLiam Girdwood */ 3240414c70cbSLiam Girdwood void *regulator_get_drvdata(struct regulator *regulator) 3241414c70cbSLiam Girdwood { 3242414c70cbSLiam Girdwood return regulator->rdev->reg_data; 3243414c70cbSLiam Girdwood } 3244414c70cbSLiam Girdwood EXPORT_SYMBOL_GPL(regulator_get_drvdata); 3245414c70cbSLiam Girdwood 3246414c70cbSLiam Girdwood /** 3247414c70cbSLiam Girdwood * regulator_set_drvdata - set regulator driver data 3248414c70cbSLiam Girdwood * @regulator: regulator 3249414c70cbSLiam Girdwood * @data: data 3250414c70cbSLiam Girdwood */ 3251414c70cbSLiam Girdwood void regulator_set_drvdata(struct regulator *regulator, void *data) 3252414c70cbSLiam Girdwood { 3253414c70cbSLiam Girdwood regulator->rdev->reg_data = data; 3254414c70cbSLiam Girdwood } 3255414c70cbSLiam Girdwood EXPORT_SYMBOL_GPL(regulator_set_drvdata); 3256414c70cbSLiam Girdwood 3257414c70cbSLiam Girdwood /** 3258414c70cbSLiam Girdwood * regulator_get_id - get regulator ID 325969279fb9SMark Brown * @rdev: regulator 3260414c70cbSLiam Girdwood */ 3261414c70cbSLiam Girdwood int rdev_get_id(struct regulator_dev *rdev) 3262414c70cbSLiam Girdwood { 3263414c70cbSLiam Girdwood return rdev->desc->id; 3264414c70cbSLiam Girdwood } 3265414c70cbSLiam Girdwood EXPORT_SYMBOL_GPL(rdev_get_id); 3266414c70cbSLiam Girdwood 3267a5766f11SLiam Girdwood struct device *rdev_get_dev(struct regulator_dev *rdev) 3268a5766f11SLiam Girdwood { 3269a5766f11SLiam Girdwood return &rdev->dev; 3270a5766f11SLiam Girdwood } 3271a5766f11SLiam Girdwood EXPORT_SYMBOL_GPL(rdev_get_dev); 3272a5766f11SLiam Girdwood 3273a5766f11SLiam Girdwood void *regulator_get_init_drvdata(struct regulator_init_data *reg_init_data) 3274a5766f11SLiam Girdwood { 3275a5766f11SLiam Girdwood return reg_init_data->driver_data; 3276a5766f11SLiam Girdwood } 3277a5766f11SLiam Girdwood EXPORT_SYMBOL_GPL(regulator_get_init_drvdata); 3278a5766f11SLiam Girdwood 3279ba55a974SMark Brown #ifdef CONFIG_DEBUG_FS 3280ba55a974SMark Brown static ssize_t supply_map_read_file(struct file *file, char __user *user_buf, 3281ba55a974SMark Brown size_t count, loff_t *ppos) 3282ba55a974SMark Brown { 3283ba55a974SMark Brown char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL); 3284ba55a974SMark Brown ssize_t len, ret = 0; 3285ba55a974SMark Brown struct regulator_map *map; 3286ba55a974SMark Brown 3287ba55a974SMark Brown if (!buf) 3288ba55a974SMark Brown return -ENOMEM; 3289ba55a974SMark Brown 3290ba55a974SMark Brown list_for_each_entry(map, ®ulator_map_list, list) { 3291ba55a974SMark Brown len = snprintf(buf + ret, PAGE_SIZE - ret, 3292ba55a974SMark Brown "%s -> %s.%s\n", 3293ba55a974SMark Brown rdev_get_name(map->regulator), map->dev_name, 3294ba55a974SMark Brown map->supply); 3295ba55a974SMark Brown if (len >= 0) 3296ba55a974SMark Brown ret += len; 3297ba55a974SMark Brown if (ret > PAGE_SIZE) { 3298ba55a974SMark Brown ret = PAGE_SIZE; 3299ba55a974SMark Brown break; 3300ba55a974SMark Brown } 3301ba55a974SMark Brown } 3302ba55a974SMark Brown 3303ba55a974SMark Brown ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret); 3304ba55a974SMark Brown 3305ba55a974SMark Brown kfree(buf); 3306ba55a974SMark Brown 3307ba55a974SMark Brown return ret; 3308ba55a974SMark Brown } 330924751434SStephen Boyd #endif 3310ba55a974SMark Brown 3311ba55a974SMark Brown static const struct file_operations supply_map_fops = { 331224751434SStephen Boyd #ifdef CONFIG_DEBUG_FS 3313ba55a974SMark Brown .read = supply_map_read_file, 3314ba55a974SMark Brown .llseek = default_llseek, 3315ba55a974SMark Brown #endif 331624751434SStephen Boyd }; 3317ba55a974SMark Brown 3318414c70cbSLiam Girdwood static int __init regulator_init(void) 3319414c70cbSLiam Girdwood { 332034abbd68SMark Brown int ret; 332134abbd68SMark Brown 332234abbd68SMark Brown ret = class_register(®ulator_class); 332334abbd68SMark Brown 33241130e5b3SMark Brown debugfs_root = debugfs_create_dir("regulator", NULL); 332524751434SStephen Boyd if (!debugfs_root) 33261130e5b3SMark Brown pr_warn("regulator: Failed to create debugfs directory\n"); 3327ba55a974SMark Brown 3328f4d562c6SMark Brown debugfs_create_file("supply_map", 0444, debugfs_root, NULL, 3329f4d562c6SMark Brown &supply_map_fops); 33301130e5b3SMark Brown 333134abbd68SMark Brown regulator_dummy_init(); 333234abbd68SMark Brown 333334abbd68SMark Brown return ret; 3334414c70cbSLiam Girdwood } 3335414c70cbSLiam Girdwood 3336414c70cbSLiam Girdwood /* init early to allow our consumers to complete system booting */ 3337414c70cbSLiam Girdwood core_initcall(regulator_init); 3338ca725561SMark Brown 3339ca725561SMark Brown static int __init regulator_init_complete(void) 3340ca725561SMark Brown { 3341ca725561SMark Brown struct regulator_dev *rdev; 3342ca725561SMark Brown struct regulator_ops *ops; 3343ca725561SMark Brown struct regulation_constraints *c; 3344ca725561SMark Brown int enabled, ret; 3345ca725561SMark Brown 3346ca725561SMark Brown mutex_lock(®ulator_list_mutex); 3347ca725561SMark Brown 3348ca725561SMark Brown /* If we have a full configuration then disable any regulators 3349ca725561SMark Brown * which are not in use or always_on. This will become the 3350ca725561SMark Brown * default behaviour in the future. 3351ca725561SMark Brown */ 3352ca725561SMark Brown list_for_each_entry(rdev, ®ulator_list, list) { 3353ca725561SMark Brown ops = rdev->desc->ops; 3354ca725561SMark Brown c = rdev->constraints; 3355ca725561SMark Brown 3356f25e0b4fSMark Brown if (!ops->disable || (c && c->always_on)) 3357ca725561SMark Brown continue; 3358ca725561SMark Brown 3359ca725561SMark Brown mutex_lock(&rdev->mutex); 3360ca725561SMark Brown 3361ca725561SMark Brown if (rdev->use_count) 3362ca725561SMark Brown goto unlock; 3363ca725561SMark Brown 3364ca725561SMark Brown /* If we can't read the status assume it's on. */ 3365ca725561SMark Brown if (ops->is_enabled) 3366ca725561SMark Brown enabled = ops->is_enabled(rdev); 3367ca725561SMark Brown else 3368ca725561SMark Brown enabled = 1; 3369ca725561SMark Brown 3370ca725561SMark Brown if (!enabled) 3371ca725561SMark Brown goto unlock; 3372ca725561SMark Brown 3373ca725561SMark Brown if (has_full_constraints) { 3374ca725561SMark Brown /* We log since this may kill the system if it 3375ca725561SMark Brown * goes wrong. */ 33765da84fd9SJoe Perches rdev_info(rdev, "disabling\n"); 3377ca725561SMark Brown ret = ops->disable(rdev); 3378ca725561SMark Brown if (ret != 0) { 33795da84fd9SJoe Perches rdev_err(rdev, "couldn't disable: %d\n", ret); 3380ca725561SMark Brown } 3381ca725561SMark Brown } else { 3382ca725561SMark Brown /* The intention is that in future we will 3383ca725561SMark Brown * assume that full constraints are provided 3384ca725561SMark Brown * so warn even if we aren't going to do 3385ca725561SMark Brown * anything here. 3386ca725561SMark Brown */ 33875da84fd9SJoe Perches rdev_warn(rdev, "incomplete constraints, leaving on\n"); 3388ca725561SMark Brown } 3389ca725561SMark Brown 3390ca725561SMark Brown unlock: 3391ca725561SMark Brown mutex_unlock(&rdev->mutex); 3392ca725561SMark Brown } 3393ca725561SMark Brown 3394ca725561SMark Brown mutex_unlock(®ulator_list_mutex); 3395ca725561SMark Brown 3396ca725561SMark Brown return 0; 3397ca725561SMark Brown } 3398ca725561SMark Brown late_initcall(regulator_init_complete); 3399