diff options
Diffstat (limited to 'drivers/regulator/core.c')
-rw-r--r-- | drivers/regulator/core.c | 201 |
1 files changed, 102 insertions, 99 deletions
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 09a737c868b5..e8ee20095a19 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -108,28 +108,6 @@ static const char *rdev_get_name(struct regulator_dev *rdev) return ""; } -/* gets the regulator for a given consumer device */ -static struct regulator *get_device_regulator(struct device *dev) -{ - struct regulator *regulator = NULL; - struct regulator_dev *rdev; - - mutex_lock(®ulator_list_mutex); - list_for_each_entry(rdev, ®ulator_list, list) { - mutex_lock(&rdev->mutex); - list_for_each_entry(regulator, &rdev->consumer_list, list) { - if (regulator->dev == dev) { - mutex_unlock(&rdev->mutex); - mutex_unlock(®ulator_list_mutex); - return regulator; - } - } - mutex_unlock(&rdev->mutex); - } - mutex_unlock(®ulator_list_mutex); - return NULL; -} - /** * of_get_regulator - get a regulator device node based on supply name * @dev: Device pointer for the consumer (of regulator) device @@ -303,18 +281,6 @@ static int regulator_check_drms(struct regulator_dev *rdev) return 0; } -static ssize_t device_requested_uA_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct regulator *regulator; - - regulator = get_device_regulator(dev); - if (regulator == NULL) - return 0; - - return sprintf(buf, "%d\n", regulator->uA_load); -} - static ssize_t regulator_uV_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -427,6 +393,9 @@ static ssize_t regulator_status_show(struct device *dev, case REGULATOR_STATUS_STANDBY: label = "standby"; break; + case REGULATOR_STATUS_UNDEFINED: + label = "undefined"; + break; default: return -ERANGE; } @@ -1097,48 +1066,29 @@ static struct regulator *create_regulator(struct regulator_dev *rdev, list_add(®ulator->list, &rdev->consumer_list); if (dev) { - /* create a 'requested_microamps_name' sysfs entry */ - size = scnprintf(buf, REG_STR_SIZE, - "microamps_requested_%s-%s", - dev_name(dev), supply_name); - if (size >= REG_STR_SIZE) - goto overflow_err; - regulator->dev = dev; - sysfs_attr_init(®ulator->dev_attr.attr); - regulator->dev_attr.attr.name = kstrdup(buf, GFP_KERNEL); - if (regulator->dev_attr.attr.name == NULL) - goto attr_name_err; - - regulator->dev_attr.attr.mode = 0444; - regulator->dev_attr.show = device_requested_uA_show; - err = device_create_file(dev, ®ulator->dev_attr); - if (err < 0) { - rdev_warn(rdev, "could not add regulator_dev requested microamps sysfs entry\n"); - goto attr_name_err; - } - /* also add a link to the device sysfs entry */ + /* Add a link to the device sysfs entry */ size = scnprintf(buf, REG_STR_SIZE, "%s-%s", dev->kobj.name, supply_name); if (size >= REG_STR_SIZE) - goto attr_err; + goto overflow_err; regulator->supply_name = kstrdup(buf, GFP_KERNEL); if (regulator->supply_name == NULL) - goto attr_err; + goto overflow_err; err = sysfs_create_link(&rdev->dev.kobj, &dev->kobj, buf); if (err) { rdev_warn(rdev, "could not add device link %s err %d\n", dev->kobj.name, err); - goto link_name_err; + /* non-fatal */ } } else { regulator->supply_name = kstrdup(supply_name, GFP_KERNEL); if (regulator->supply_name == NULL) - goto attr_err; + goto overflow_err; } regulator->debugfs = debugfs_create_dir(regulator->supply_name, @@ -1165,12 +1115,6 @@ static struct regulator *create_regulator(struct regulator_dev *rdev, mutex_unlock(&rdev->mutex); return regulator; -link_name_err: - kfree(regulator->supply_name); -attr_err: - device_remove_file(regulator->dev, ®ulator->dev_attr); -attr_name_err: - kfree(regulator->dev_attr.attr.name); overflow_err: list_del(®ulator->list); kfree(regulator); @@ -1420,11 +1364,8 @@ void regulator_put(struct regulator *regulator) debugfs_remove_recursive(regulator->debugfs); /* remove any sysfs entries */ - if (regulator->dev) { + if (regulator->dev) sysfs_remove_link(&rdev->dev.kobj, regulator->supply_name); - device_remove_file(regulator->dev, ®ulator->dev_attr); - kfree(regulator->dev_attr.attr.name); - } kfree(regulator->supply_name); list_del(®ulator->list); kfree(regulator); @@ -1459,11 +1400,9 @@ void devm_regulator_put(struct regulator *regulator) { int rc; - rc = devres_destroy(regulator->dev, devm_regulator_release, + rc = devres_release(regulator->dev, devm_regulator_release, devm_regulator_match, regulator); - if (rc == 0) - regulator_put(regulator); - else + if (rc != 0) WARN_ON(rc); } EXPORT_SYMBOL_GPL(devm_regulator_put); @@ -1883,6 +1822,31 @@ int regulator_list_voltage_linear(struct regulator_dev *rdev, EXPORT_SYMBOL_GPL(regulator_list_voltage_linear); /** + * regulator_list_voltage_table - List voltages with table based mapping + * + * @rdev: Regulator device + * @selector: Selector to convert into a voltage + * + * Regulators with table based mapping between voltages and + * selectors can set volt_table in the regulator descriptor + * and then use this function as their list_voltage() operation. + */ +int regulator_list_voltage_table(struct regulator_dev *rdev, + unsigned int selector) +{ + if (!rdev->desc->volt_table) { + BUG_ON(!rdev->desc->volt_table); + return -EINVAL; + } + + if (selector >= rdev->desc->n_voltages) + return -EINVAL; + + return rdev->desc->volt_table[selector]; +} +EXPORT_SYMBOL_GPL(regulator_list_voltage_table); + +/** * regulator_list_voltage - enumerate supported voltages * @regulator: regulator source * @selector: identify voltage to list @@ -1928,8 +1892,18 @@ EXPORT_SYMBOL_GPL(regulator_list_voltage); int regulator_is_supported_voltage(struct regulator *regulator, int min_uV, int max_uV) { + struct regulator_dev *rdev = regulator->rdev; int i, voltages, ret; + /* If we can't change voltage check the current voltage */ + if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_VOLTAGE)) { + ret = regulator_get_voltage(regulator); + if (ret >= 0) + return (min_uV >= ret && ret <= max_uV); + else + return ret; + } + ret = regulator_count_voltages(regulator); if (ret < 0) return ret; @@ -2071,7 +2045,7 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev, { int ret; int delay = 0; - int best_val; + int best_val = 0; unsigned int selector; int old_selector = -1; @@ -2084,7 +2058,8 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev, * If we can't obtain the old selector there is not enough * info to call set_voltage_time_sel(). */ - if (rdev->desc->ops->set_voltage_time_sel && + if (_regulator_is_enabled(rdev) && + rdev->desc->ops->set_voltage_time_sel && rdev->desc->ops->get_voltage_sel) { old_selector = rdev->desc->ops->get_voltage_sel(rdev); if (old_selector < 0) @@ -2094,29 +2069,45 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev, if (rdev->desc->ops->set_voltage) { ret = rdev->desc->ops->set_voltage(rdev, min_uV, max_uV, &selector); + + if (ret >= 0) { + if (rdev->desc->ops->list_voltage) + best_val = rdev->desc->ops->list_voltage(rdev, + selector); + else + best_val = _regulator_get_voltage(rdev); + } + } else if (rdev->desc->ops->set_voltage_sel) { - if (rdev->desc->ops->map_voltage) + if (rdev->desc->ops->map_voltage) { ret = rdev->desc->ops->map_voltage(rdev, min_uV, max_uV); - else - ret = regulator_map_voltage_iterate(rdev, min_uV, - max_uV); + } else { + if (rdev->desc->ops->list_voltage == + regulator_list_voltage_linear) + ret = regulator_map_voltage_linear(rdev, + min_uV, max_uV); + else + ret = regulator_map_voltage_iterate(rdev, + min_uV, max_uV); + } if (ret >= 0) { - selector = ret; - ret = rdev->desc->ops->set_voltage_sel(rdev, ret); + best_val = rdev->desc->ops->list_voltage(rdev, ret); + if (min_uV <= best_val && max_uV >= best_val) { + selector = ret; + ret = rdev->desc->ops->set_voltage_sel(rdev, + ret); + } else { + ret = -EINVAL; + } } } else { ret = -EINVAL; } - if (rdev->desc->ops->list_voltage) - best_val = rdev->desc->ops->list_voltage(rdev, selector); - else - best_val = -1; - /* Call set_voltage_time_sel if successfully obtained old_selector */ - if (ret == 0 && old_selector >= 0 && + if (ret == 0 && _regulator_is_enabled(rdev) && old_selector >= 0 && rdev->desc->ops->set_voltage_time_sel) { delay = rdev->desc->ops->set_voltage_time_sel(rdev, @@ -2126,19 +2117,19 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev, delay); delay = 0; } - } - /* Insert any necessary delays */ - if (delay >= 1000) { - mdelay(delay / 1000); - udelay(delay % 1000); - } else if (delay) { - udelay(delay); + /* Insert any necessary delays */ + if (delay >= 1000) { + mdelay(delay / 1000); + udelay(delay % 1000); + } else if (delay) { + udelay(delay); + } } - if (ret == 0) + if (ret == 0 && best_val >= 0) _notifier_call_chain(rdev, REGULATOR_EVENT_VOLTAGE_CHANGE, - NULL); + (void *)best_val); trace_regulator_set_voltage_complete(rdev_get_name(rdev), best_val); @@ -2628,7 +2619,7 @@ static void _notifier_call_chain(struct regulator_dev *rdev, unsigned long event, void *data) { /* call rdev chain first */ - blocking_notifier_call_chain(&rdev->notifier, event, NULL); + blocking_notifier_call_chain(&rdev->notifier, event, data); } /** @@ -2909,10 +2900,10 @@ int regulator_mode_to_status(unsigned int mode) return REGULATOR_STATUS_NORMAL; case REGULATOR_MODE_IDLE: return REGULATOR_STATUS_IDLE; - case REGULATOR_STATUS_STANDBY: + case REGULATOR_MODE_STANDBY: return REGULATOR_STATUS_STANDBY; default: - return 0; + return REGULATOR_STATUS_UNDEFINED; } } EXPORT_SYMBOL_GPL(regulator_mode_to_status); @@ -3105,7 +3096,10 @@ regulator_register(const struct regulator_desc *regulator_desc, rdev->reg_data = config->driver_data; rdev->owner = regulator_desc->owner; rdev->desc = regulator_desc; - rdev->regmap = config->regmap; + if (config->regmap) + rdev->regmap = config->regmap; + else + rdev->regmap = dev_get_regmap(dev, NULL); INIT_LIST_HEAD(&rdev->consumer_list); INIT_LIST_HEAD(&rdev->list); BLOCKING_INIT_NOTIFIER_HEAD(&rdev->notifier); @@ -3472,6 +3466,15 @@ static int __init regulator_init_complete(void) struct regulation_constraints *c; int enabled, ret; + /* + * Since DT doesn't provide an idiomatic mechanism for + * enabling full constraints and since it's much more natural + * with DT to provide them just assume that a DT enabled + * system has full constraints. + */ + if (of_have_populated_dt()) + has_full_constraints = true; + mutex_lock(®ulator_list_mutex); /* If we have a full configuration then disable any regulators |