diff options
Diffstat (limited to 'drivers/regulator/core.c')
| -rw-r--r-- | drivers/regulator/core.c | 601 | 
1 files changed, 334 insertions, 267 deletions
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index a01b8b3b70c..4c1f999041d 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -36,6 +36,7 @@  #include <trace/events/regulator.h>  #include "dummy.h" +#include "internal.h"  #define rdev_crit(rdev, fmt, ...)					\  	pr_crit("%s: " fmt, rdev_get_name(rdev), ##__VA_ARGS__) @@ -52,8 +53,8 @@ static DEFINE_MUTEX(regulator_list_mutex);  static LIST_HEAD(regulator_list);  static LIST_HEAD(regulator_map_list);  static LIST_HEAD(regulator_ena_gpio_list); +static LIST_HEAD(regulator_supply_alias_list);  static bool has_full_constraints; -static bool board_wants_dummy_regulator;  static struct dentry *debugfs_root; @@ -83,22 +84,16 @@ struct regulator_enable_gpio {  };  /* - * struct regulator + * struct regulator_supply_alias   * - * One for each consumer device. + * Used to map lookups for a supply onto an alternative device.   */ -struct regulator { -	struct device *dev; +struct regulator_supply_alias {  	struct list_head list; -	unsigned int always_on:1; -	unsigned int bypass:1; -	int uA_load; -	int min_uV; -	int max_uV; -	char *supply_name; -	struct device_attribute dev_attr; -	struct regulator_dev *rdev; -	struct dentry *debugfs; +	struct device *src_dev; +	const char *src_supply; +	struct device *alias_dev; +	const char *alias_supply;  };  static int _regulator_is_enabled(struct regulator_dev *rdev); @@ -124,6 +119,11 @@ static const char *rdev_get_name(struct regulator_dev *rdev)  		return "";  } +static bool have_full_constraints(void) +{ +	return has_full_constraints || of_have_populated_dt(); +} +  /**   * of_get_regulator - get a regulator device node based on supply name   * @dev: Device pointer for the consumer (of regulator) device @@ -844,13 +844,22 @@ static int machine_constraints_voltage(struct regulator_dev *rdev,  	/* do we need to apply the constraint voltage */  	if (rdev->constraints->apply_uV &&  	    rdev->constraints->min_uV == rdev->constraints->max_uV) { -		ret = _regulator_do_set_voltage(rdev, -						rdev->constraints->min_uV, -						rdev->constraints->max_uV); -		if (ret < 0) { -			rdev_err(rdev, "failed to apply %duV constraint\n", -				 rdev->constraints->min_uV); -			return ret; +		int current_uV = _regulator_get_voltage(rdev); +		if (current_uV < 0) { +			rdev_err(rdev, "failed to get the current voltage\n"); +			return current_uV; +		} +		if (current_uV < rdev->constraints->min_uV || +		    current_uV > rdev->constraints->max_uV) { +			ret = _regulator_do_set_voltage( +				rdev, rdev->constraints->min_uV, +				rdev->constraints->max_uV); +			if (ret < 0) { +				rdev_err(rdev, +					"failed to apply %duV constraint\n", +					rdev->constraints->min_uV); +				return ret; +			}  		}  	} @@ -923,6 +932,38 @@ static int machine_constraints_voltage(struct regulator_dev *rdev,  	return 0;  } +static int machine_constraints_current(struct regulator_dev *rdev, +	struct regulation_constraints *constraints) +{ +	struct regulator_ops *ops = rdev->desc->ops; +	int ret; + +	if (!constraints->min_uA && !constraints->max_uA) +		return 0; + +	if (constraints->min_uA > constraints->max_uA) { +		rdev_err(rdev, "Invalid current constraints\n"); +		return -EINVAL; +	} + +	if (!ops->set_current_limit || !ops->get_current_limit) { +		rdev_warn(rdev, "Operation of current configuration missing\n"); +		return 0; +	} + +	/* Set regulator current in constraints range */ +	ret = ops->set_current_limit(rdev, constraints->min_uA, +			constraints->max_uA); +	if (ret < 0) { +		rdev_err(rdev, "Failed to set current constraint, %d\n", ret); +		return ret; +	} + +	return 0; +} + +static int _regulator_do_enable(struct regulator_dev *rdev); +  /**   * set_machine_constraints - sets regulator constraints   * @rdev: regulator source @@ -953,6 +994,10 @@ static int set_machine_constraints(struct regulator_dev *rdev,  	if (ret != 0)  		goto out; +	ret = machine_constraints_current(rdev, rdev->constraints); +	if (ret != 0) +		goto out; +  	/* do we need to setup our suspend state */  	if (rdev->constraints->initial_state) {  		ret = suspend_prepare(rdev, rdev->constraints->initial_state); @@ -979,10 +1024,9 @@ static int set_machine_constraints(struct regulator_dev *rdev,  	/* If the constraints say the regulator should be on at this point  	 * and we have control then make sure it is enabled.  	 */ -	if ((rdev->constraints->always_on || rdev->constraints->boot_on) && -	    ops->enable) { -		ret = ops->enable(rdev); -		if (ret < 0) { +	if (rdev->constraints->always_on || rdev->constraints->boot_on) { +		ret = _regulator_do_enable(rdev); +		if (ret < 0 && ret != -EINVAL) {  			rdev_err(rdev, "failed to enable\n");  			goto out;  		} @@ -1186,11 +1230,39 @@ overflow_err:  static int _regulator_get_enable_time(struct regulator_dev *rdev)  { +	if (rdev->constraints && rdev->constraints->enable_time) +		return rdev->constraints->enable_time;  	if (!rdev->desc->ops->enable_time)  		return rdev->desc->enable_time;  	return rdev->desc->ops->enable_time(rdev);  } +static struct regulator_supply_alias *regulator_find_supply_alias( +		struct device *dev, const char *supply) +{ +	struct regulator_supply_alias *map; + +	list_for_each_entry(map, ®ulator_supply_alias_list, list) +		if (map->src_dev == dev && strcmp(map->src_supply, supply) == 0) +			return map; + +	return NULL; +} + +static void regulator_supply_alias(struct device **dev, const char **supply) +{ +	struct regulator_supply_alias *map; + +	map = regulator_find_supply_alias(*dev, *supply); +	if (map) { +		dev_dbg(*dev, "Mapping supply %s to %s,%s\n", +				*supply, map->alias_supply, +				dev_name(map->alias_dev)); +		*dev = map->alias_dev; +		*supply = map->alias_supply; +	} +} +  static struct regulator_dev *regulator_dev_lookup(struct device *dev,  						  const char *supply,  						  int *ret) @@ -1200,6 +1272,8 @@ static struct regulator_dev *regulator_dev_lookup(struct device *dev,  	struct regulator_map *map;  	const char *devname = NULL; +	regulator_supply_alias(&dev, &supply); +  	/* first do a dt based lookup */  	if (dev && dev->of_node) {  		node = of_get_regulator(dev, supply); @@ -1208,6 +1282,8 @@ static struct regulator_dev *regulator_dev_lookup(struct device *dev,  				if (r->dev.parent &&  					node == r->dev.of_node)  					return r; +			*ret = -EPROBE_DEFER; +			return NULL;  		} else {  			/*  			 * If we couldn't even get the node then it's @@ -1243,55 +1319,58 @@ static struct regulator_dev *regulator_dev_lookup(struct device *dev,  /* Internal regulator request function */  static struct regulator *_regulator_get(struct device *dev, const char *id, -					bool exclusive) +					bool exclusive, bool allow_dummy)  {  	struct regulator_dev *rdev;  	struct regulator *regulator = ERR_PTR(-EPROBE_DEFER);  	const char *devname = NULL; -	int ret = 0; +	int ret;  	if (id == NULL) {  		pr_err("get() with no identifier\n"); -		return regulator; +		return ERR_PTR(-EINVAL);  	}  	if (dev)  		devname = dev_name(dev); +	if (have_full_constraints()) +		ret = -ENODEV; +	else +		ret = -EPROBE_DEFER; +  	mutex_lock(®ulator_list_mutex);  	rdev = regulator_dev_lookup(dev, id, &ret);  	if (rdev)  		goto found; +	regulator = ERR_PTR(ret); +  	/*  	 * If we have return value from dev_lookup fail, we do not expect to  	 * succeed, so, quit with appropriate error value  	 */ -	if (ret) { -		regulator = ERR_PTR(ret); +	if (ret && ret != -ENODEV)  		goto out; -	} - -	if (board_wants_dummy_regulator) { -		rdev = dummy_regulator_rdev; -		goto found; -	} -#ifdef CONFIG_REGULATOR_DUMMY  	if (!devname)  		devname = "deviceless"; -	/* If the board didn't flag that it was fully constrained then -	 * substitute in a dummy regulator so consumers can continue. +	/* +	 * Assume that a regulator is physically present and enabled +	 * even if it isn't hooked up and just provide a dummy.  	 */ -	if (!has_full_constraints) { +	if (have_full_constraints() && allow_dummy) {  		pr_warn("%s supply %s not found, using dummy regulator\n",  			devname, id); +  		rdev = dummy_regulator_rdev;  		goto found; +	/* Don't log an error when called from regulator_get_optional() */ +	} else if (!have_full_constraints() || exclusive) { +		dev_warn(dev, "dummy supplies not allowed\n");  	} -#endif  	mutex_unlock(®ulator_list_mutex);  	return regulator; @@ -1349,44 +1428,10 @@ out:   */  struct regulator *regulator_get(struct device *dev, const char *id)  { -	return _regulator_get(dev, id, false); +	return _regulator_get(dev, id, false, true);  }  EXPORT_SYMBOL_GPL(regulator_get); -static void devm_regulator_release(struct device *dev, void *res) -{ -	regulator_put(*(struct regulator **)res); -} - -/** - * devm_regulator_get - Resource managed regulator_get() - * @dev: device for regulator "consumer" - * @id: Supply name or regulator ID. - * - * Managed regulator_get(). Regulators returned from this function are - * automatically regulator_put() on driver detach. See regulator_get() for more - * information. - */ -struct regulator *devm_regulator_get(struct device *dev, const char *id) -{ -	struct regulator **ptr, *regulator; - -	ptr = devres_alloc(devm_regulator_release, sizeof(*ptr), GFP_KERNEL); -	if (!ptr) -		return ERR_PTR(-ENOMEM); - -	regulator = regulator_get(dev, id); -	if (!IS_ERR(regulator)) { -		*ptr = regulator; -		devres_add(dev, ptr); -	} else { -		devres_free(ptr); -	} - -	return regulator; -} -EXPORT_SYMBOL_GPL(devm_regulator_get); -  /**   * regulator_get_exclusive - obtain exclusive access to a regulator.   * @dev: device for regulator "consumer" @@ -1394,9 +1439,9 @@ EXPORT_SYMBOL_GPL(devm_regulator_get);   *   * Returns a struct regulator corresponding to the regulator producer,   * or IS_ERR() condition containing errno.  Other consumers will be - * unable to obtain this reference is held and the use count for the - * regulator will be initialised to reflect the current state of the - * regulator. + * unable to obtain this regulator while this reference is held and the + * use count for the regulator will be initialised to reflect the current + * state of the regulator.   *   * This is intended for use by consumers which cannot tolerate shared   * use of the regulator such as those which need to force the @@ -1410,7 +1455,7 @@ EXPORT_SYMBOL_GPL(devm_regulator_get);   */  struct regulator *regulator_get_exclusive(struct device *dev, const char *id)  { -	return _regulator_get(dev, id, true); +	return _regulator_get(dev, id, true, false);  }  EXPORT_SYMBOL_GPL(regulator_get_exclusive); @@ -1420,10 +1465,7 @@ EXPORT_SYMBOL_GPL(regulator_get_exclusive);   * @id: Supply name or regulator ID.   *   * Returns a struct regulator corresponding to the regulator producer, - * or IS_ERR() condition containing errno.  Other consumers will be - * unable to obtain this reference is held and the use count for the - * regulator will be initialised to reflect the current state of the - * regulator. + * or IS_ERR() condition containing errno.   *   * This is intended for use by consumers for devices which can have   * some supplies unconnected in normal use, such as some MMC devices. @@ -1439,40 +1481,10 @@ EXPORT_SYMBOL_GPL(regulator_get_exclusive);   */  struct regulator *regulator_get_optional(struct device *dev, const char *id)  { -	return _regulator_get(dev, id, 0); +	return _regulator_get(dev, id, false, false);  }  EXPORT_SYMBOL_GPL(regulator_get_optional); -/** - * devm_regulator_get_optional - Resource managed regulator_get_optional() - * @dev: device for regulator "consumer" - * @id: Supply name or regulator ID. - * - * Managed regulator_get_optional(). Regulators returned from this - * function are automatically regulator_put() on driver detach. See - * regulator_get_optional() for more information. - */ -struct regulator *devm_regulator_get_optional(struct device *dev, -					      const char *id) -{ -	struct regulator **ptr, *regulator; - -	ptr = devres_alloc(devm_regulator_release, sizeof(*ptr), GFP_KERNEL); -	if (!ptr) -		return ERR_PTR(-ENOMEM); - -	regulator = regulator_get_optional(dev, id); -	if (!IS_ERR(regulator)) { -		*ptr = regulator; -		devres_add(dev, ptr); -	} else { -		devres_free(ptr); -	} - -	return regulator; -} -EXPORT_SYMBOL_GPL(devm_regulator_get_optional); -  /* Locks held by regulator_put() */  static void _regulator_put(struct regulator *regulator)  { @@ -1499,36 +1511,6 @@ static void _regulator_put(struct regulator *regulator)  }  /** - * devm_regulator_get_exclusive - Resource managed regulator_get_exclusive() - * @dev: device for regulator "consumer" - * @id: Supply name or regulator ID. - * - * Managed regulator_get_exclusive(). Regulators returned from this function - * are automatically regulator_put() on driver detach. See regulator_get() for - * more information. - */ -struct regulator *devm_regulator_get_exclusive(struct device *dev, -					       const char *id) -{ -	struct regulator **ptr, *regulator; - -	ptr = devres_alloc(devm_regulator_release, sizeof(*ptr), GFP_KERNEL); -	if (!ptr) -		return ERR_PTR(-ENOMEM); - -	regulator = _regulator_get(dev, id, 1); -	if (!IS_ERR(regulator)) { -		*ptr = regulator; -		devres_add(dev, ptr); -	} else { -		devres_free(ptr); -	} - -	return regulator; -} -EXPORT_SYMBOL_GPL(devm_regulator_get_exclusive); - -/**   * regulator_put - "free" the regulator source   * @regulator: regulator source   * @@ -1544,34 +1526,134 @@ void regulator_put(struct regulator *regulator)  }  EXPORT_SYMBOL_GPL(regulator_put); -static int devm_regulator_match(struct device *dev, void *res, void *data) +/** + * regulator_register_supply_alias - Provide device alias for supply lookup + * + * @dev: device that will be given as the regulator "consumer" + * @id: Supply name or regulator ID + * @alias_dev: device that should be used to lookup the supply + * @alias_id: Supply name or regulator ID that should be used to lookup the + * supply + * + * All lookups for id on dev will instead be conducted for alias_id on + * alias_dev. + */ +int regulator_register_supply_alias(struct device *dev, const char *id, +				    struct device *alias_dev, +				    const char *alias_id)  { -	struct regulator **r = res; -	if (!r || !*r) { -		WARN_ON(!r || !*r); -		return 0; +	struct regulator_supply_alias *map; + +	map = regulator_find_supply_alias(dev, id); +	if (map) +		return -EEXIST; + +	map = kzalloc(sizeof(struct regulator_supply_alias), GFP_KERNEL); +	if (!map) +		return -ENOMEM; + +	map->src_dev = dev; +	map->src_supply = id; +	map->alias_dev = alias_dev; +	map->alias_supply = alias_id; + +	list_add(&map->list, ®ulator_supply_alias_list); + +	pr_info("Adding alias for supply %s,%s -> %s,%s\n", +		id, dev_name(dev), alias_id, dev_name(alias_dev)); + +	return 0; +} +EXPORT_SYMBOL_GPL(regulator_register_supply_alias); + +/** + * regulator_unregister_supply_alias - Remove device alias + * + * @dev: device that will be given as the regulator "consumer" + * @id: Supply name or regulator ID + * + * Remove a lookup alias if one exists for id on dev. + */ +void regulator_unregister_supply_alias(struct device *dev, const char *id) +{ +	struct regulator_supply_alias *map; + +	map = regulator_find_supply_alias(dev, id); +	if (map) { +		list_del(&map->list); +		kfree(map); +	} +} +EXPORT_SYMBOL_GPL(regulator_unregister_supply_alias); + +/** + * regulator_bulk_register_supply_alias - register multiple aliases + * + * @dev: device that will be given as the regulator "consumer" + * @id: List of supply names or regulator IDs + * @alias_dev: device that should be used to lookup the supply + * @alias_id: List of supply names or regulator IDs that should be used to + * lookup the supply + * @num_id: Number of aliases to register + * + * @return 0 on success, an errno on failure. + * + * This helper function allows drivers to register several supply + * aliases in one operation.  If any of the aliases cannot be + * registered any aliases that were registered will be removed + * before returning to the caller. + */ +int regulator_bulk_register_supply_alias(struct device *dev, +					 const char *const *id, +					 struct device *alias_dev, +					 const char *const *alias_id, +					 int num_id) +{ +	int i; +	int ret; + +	for (i = 0; i < num_id; ++i) { +		ret = regulator_register_supply_alias(dev, id[i], alias_dev, +						      alias_id[i]); +		if (ret < 0) +			goto err;  	} -	return *r == data; + +	return 0; + +err: +	dev_err(dev, +		"Failed to create supply alias %s,%s -> %s,%s\n", +		id[i], dev_name(dev), alias_id[i], dev_name(alias_dev)); + +	while (--i >= 0) +		regulator_unregister_supply_alias(dev, id[i]); + +	return ret;  } +EXPORT_SYMBOL_GPL(regulator_bulk_register_supply_alias);  /** - * devm_regulator_put - Resource managed regulator_put() - * @regulator: regulator to free + * regulator_bulk_unregister_supply_alias - unregister multiple aliases   * - * Deallocate a regulator allocated with devm_regulator_get(). Normally - * this function will not need to be called and the resource management - * code will ensure that the resource is freed. + * @dev: device that will be given as the regulator "consumer" + * @id: List of supply names or regulator IDs + * @num_id: Number of aliases to unregister + * + * This helper function allows drivers to unregister several supply + * aliases in one operation.   */ -void devm_regulator_put(struct regulator *regulator) +void regulator_bulk_unregister_supply_alias(struct device *dev, +					    const char *const *id, +					    int num_id)  { -	int rc; +	int i; -	rc = devres_release(regulator->dev, devm_regulator_release, -			    devm_regulator_match, regulator); -	if (rc != 0) -		WARN_ON(rc); +	for (i = 0; i < num_id; ++i) +		regulator_unregister_supply_alias(dev, id[i]);  } -EXPORT_SYMBOL_GPL(devm_regulator_put); +EXPORT_SYMBOL_GPL(regulator_bulk_unregister_supply_alias); +  /* Manage enable GPIO list. Same GPIO pin can be shared among regulators */  static int regulator_ena_gpio_request(struct regulator_dev *rdev, @@ -1704,11 +1786,39 @@ static int _regulator_do_enable(struct regulator_dev *rdev)  	 * together.  */  	trace_regulator_enable_delay(rdev_get_name(rdev)); -	if (delay >= 1000) { -		mdelay(delay / 1000); -		udelay(delay % 1000); -	} else if (delay) { -		udelay(delay); +	/* +	 * Delay for the requested amount of time as per the guidelines in: +	 * +	 *     Documentation/timers/timers-howto.txt +	 * +	 * The assumption here is that regulators will never be enabled in +	 * atomic context and therefore sleeping functions can be used. +	 */ +	if (delay) { +		unsigned int ms = delay / 1000; +		unsigned int us = delay % 1000; + +		if (ms > 0) { +			/* +			 * For small enough values, handle super-millisecond +			 * delays in the usleep_range() call below. +			 */ +			if (ms < 20) +				us += ms * 1000; +			else +				msleep(ms); +		} + +		/* +		 * Give the scheduler some room to coalesce with any other +		 * wakeup sources. For delays shorter than 10 us, don't even +		 * bother setting up high-resolution timers and just busy- +		 * loop. +		 */ +		if (us >= 10) +			usleep_range(us, us + 100); +		else +			udelay(us);  	}  	trace_regulator_enable_complete(rdev_get_name(rdev)); @@ -1805,8 +1915,6 @@ static int _regulator_do_disable(struct regulator_dev *rdev)  	trace_regulator_disable_complete(rdev_get_name(rdev)); -	_notifier_call_chain(rdev, REGULATOR_EVENT_DISABLE, -			     NULL);  	return 0;  } @@ -1830,6 +1938,8 @@ static int _regulator_disable(struct regulator_dev *rdev)  				rdev_err(rdev, "failed to disable\n");  				return ret;  			} +			_notifier_call_chain(rdev, REGULATOR_EVENT_DISABLE, +					NULL);  		}  		rdev->use_count = 0; @@ -1882,20 +1992,16 @@ static int _regulator_force_disable(struct regulator_dev *rdev)  {  	int ret = 0; -	/* force disable */ -	if (rdev->desc->ops->disable) { -		/* ah well, who wants to live forever... */ -		ret = rdev->desc->ops->disable(rdev); -		if (ret < 0) { -			rdev_err(rdev, "failed to force disable\n"); -			return ret; -		} -		/* notify other consumers that power has been forced off */ -		_notifier_call_chain(rdev, REGULATOR_EVENT_FORCE_DISABLE | -			REGULATOR_EVENT_DISABLE, NULL); +	ret = _regulator_do_disable(rdev); +	if (ret < 0) { +		rdev_err(rdev, "failed to force disable\n"); +		return ret;  	} -	return ret; +	_notifier_call_chain(rdev, REGULATOR_EVENT_FORCE_DISABLE | +			REGULATOR_EVENT_DISABLE, NULL); + +	return 0;  }  /** @@ -2039,7 +2145,7 @@ EXPORT_SYMBOL_GPL(regulator_is_enabled);   * @regulator: regulator source   *   * Returns positive if the regulator driver backing the source/client - * can change its voltage, false otherwise. Usefull for detecting fixed + * can change its voltage, false otherwise. Useful for detecting fixed   * or dummy regulators and disabling voltage change logic in the client   * driver.   */ @@ -2094,6 +2200,9 @@ int regulator_list_voltage(struct regulator *regulator, unsigned selector)  	struct regulator_ops	*ops = rdev->desc->ops;  	int			ret; +	if (rdev->desc->fixed_uV && rdev->desc->n_voltages == 1 && !selector) +		return rdev->desc->fixed_uV; +  	if (!ops->list_voltage || selector >= rdev->desc->n_voltages)  		return -EINVAL; @@ -2146,7 +2255,7 @@ int regulator_is_supported_voltage(struct regulator *regulator,  	if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_VOLTAGE)) {  		ret = regulator_get_voltage(regulator);  		if (ret >= 0) -			return (min_uV <= ret && ret <= max_uV); +			return min_uV <= ret && ret <= max_uV;  		else  			return ret;  	} @@ -2219,6 +2328,10 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev,  			    regulator_list_voltage_linear)  				ret = regulator_map_voltage_linear(rdev,  								min_uV, max_uV); +			else if (rdev->desc->ops->list_voltage == +				 regulator_list_voltage_linear_range) +				ret = regulator_map_voltage_linear_range(rdev, +								min_uV, max_uV);  			else  				ret = regulator_map_voltage_iterate(rdev,  								min_uV, max_uV); @@ -2297,6 +2410,7 @@ int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV)  	struct regulator_dev *rdev = regulator->rdev;  	int ret = 0;  	int old_min_uV, old_max_uV; +	int current_uV;  	mutex_lock(&rdev->mutex); @@ -2307,6 +2421,19 @@ int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV)  	if (regulator->min_uV == min_uV && regulator->max_uV == max_uV)  		goto out; +	/* If we're trying to set a range that overlaps the current voltage, +	 * return succesfully even though the regulator does not support +	 * changing the voltage. +	 */ +	if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_VOLTAGE)) { +		current_uV = _regulator_get_voltage(rdev); +		if (min_uV <= current_uV && current_uV <= max_uV) { +			regulator->min_uV = min_uV; +			regulator->max_uV = max_uV; +			goto out; +		} +	} +  	/* sanity check */  	if (!rdev->desc->ops->set_voltage &&  	    !rdev->desc->ops->set_voltage_sel) { @@ -2318,7 +2445,7 @@ int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV)  	ret = regulator_check_voltage(rdev, &min_uV, &max_uV);  	if (ret < 0)  		goto out; -	 +  	/* restore original values in case of error */  	old_min_uV = regulator->min_uV;  	old_max_uV = regulator->max_uV; @@ -2332,7 +2459,7 @@ int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV)  	ret = _regulator_do_set_voltage(rdev, min_uV, max_uV);  	if (ret < 0)  		goto out2; -	 +  out:  	mutex_unlock(&rdev->mutex);  	return ret; @@ -2489,6 +2616,8 @@ static int _regulator_get_voltage(struct regulator_dev *rdev)  		ret = rdev->desc->ops->get_voltage(rdev);  	} else if (rdev->desc->ops->list_voltage) {  		ret = rdev->desc->ops->list_voltage(rdev, 0); +	} else if (rdev->desc->fixed_uV && (rdev->desc->n_voltages == 1)) { +		ret = rdev->desc->fixed_uV;  	} else {  		return -EINVAL;  	} @@ -2912,52 +3041,6 @@ err:  }  EXPORT_SYMBOL_GPL(regulator_bulk_get); -/** - * devm_regulator_bulk_get - managed get multiple regulator consumers - * - * @dev:           Device to supply - * @num_consumers: Number of consumers to register - * @consumers:     Configuration of consumers; clients are stored here. - * - * @return 0 on success, an errno on failure. - * - * This helper function allows drivers to get several regulator - * consumers in one operation with management, the regulators will - * automatically be freed when the device is unbound.  If any of the - * regulators cannot be acquired then any regulators that were - * allocated will be freed before returning to the caller. - */ -int devm_regulator_bulk_get(struct device *dev, int num_consumers, -			    struct regulator_bulk_data *consumers) -{ -	int i; -	int ret; - -	for (i = 0; i < num_consumers; i++) -		consumers[i].consumer = NULL; - -	for (i = 0; i < num_consumers; i++) { -		consumers[i].consumer = devm_regulator_get(dev, -							   consumers[i].supply); -		if (IS_ERR(consumers[i].consumer)) { -			ret = PTR_ERR(consumers[i].consumer); -			dev_err(dev, "Failed to get supply '%s': %d\n", -				consumers[i].supply, ret); -			consumers[i].consumer = NULL; -			goto err; -		} -	} - -	return 0; - -err: -	for (i = 0; i < num_consumers && consumers[i].consumer; i++) -		devm_regulator_put(consumers[i].consumer); - -	return ret; -} -EXPORT_SYMBOL_GPL(devm_regulator_bulk_get); -  static void regulator_bulk_enable_async(void *data, async_cookie_t cookie)  {  	struct regulator_bulk_data *bulk = data; @@ -3170,7 +3253,8 @@ static int add_regulator_attributes(struct regulator_dev *rdev)  	/* some attributes need specific methods to be displayed */  	if ((ops->get_voltage && ops->get_voltage(rdev) >= 0) ||  	    (ops->get_voltage_sel && ops->get_voltage_sel(rdev) >= 0) || -	    (ops->list_voltage && ops->list_voltage(rdev, 0) >= 0)) { +	    (ops->list_voltage && ops->list_voltage(rdev, 0) >= 0) || +		(rdev->desc->fixed_uV && (rdev->desc->n_voltages == 1))) {  		status = device_create_file(dev, &dev_attr_microvolts);  		if (status < 0)  			return status; @@ -3374,7 +3458,7 @@ regulator_register(const struct regulator_desc *regulator_desc,  	/* register with sysfs */  	rdev->dev.class = ®ulator_class; -	rdev->dev.of_node = config->of_node; +	rdev->dev.of_node = of_node_get(config->of_node);  	rdev->dev.parent = dev;  	dev_set_name(&rdev->dev, "regulator.%d",  		     atomic_inc_return(®ulator_no) - 1); @@ -3516,6 +3600,7 @@ void regulator_unregister(struct regulator_dev *rdev)  	list_del(&rdev->list);  	kfree(rdev->constraints);  	regulator_ena_gpio_free(rdev); +	of_node_put(rdev->dev.of_node);  	device_unregister(&rdev->dev);  	mutex_unlock(®ulator_list_mutex);  } @@ -3568,23 +3653,18 @@ int regulator_suspend_finish(void)  	mutex_lock(®ulator_list_mutex);  	list_for_each_entry(rdev, ®ulator_list, list) { -		struct regulator_ops *ops = rdev->desc->ops; -  		mutex_lock(&rdev->mutex); -		if ((rdev->use_count > 0  || rdev->constraints->always_on) && -				ops->enable) { -			error = ops->enable(rdev); +		if (rdev->use_count > 0  || rdev->constraints->always_on) { +			error = _regulator_do_enable(rdev);  			if (error)  				ret = error;  		} else { -			if (!has_full_constraints) -				goto unlock; -			if (!ops->disable) +			if (!have_full_constraints())  				goto unlock;  			if (!_regulator_is_enabled(rdev))  				goto unlock; -			error = ops->disable(rdev); +			error = _regulator_do_disable(rdev);  			if (error)  				ret = error;  		} @@ -3614,22 +3694,6 @@ void regulator_has_full_constraints(void)  EXPORT_SYMBOL_GPL(regulator_has_full_constraints);  /** - * regulator_use_dummy_regulator - Provide a dummy regulator when none is found - * - * Calling this function will cause the regulator API to provide a - * dummy regulator to consumers if no physical regulator is found, - * allowing most consumers to proceed as though a regulator were - * configured.  This allows systems such as those with software - * controllable regulators for the CPU core only to be brought up more - * readily. - */ -void regulator_use_dummy_regulator(void) -{ -	board_wants_dummy_regulator = true; -} -EXPORT_SYMBOL_GPL(regulator_use_dummy_regulator); - -/**   * rdev_get_drvdata - get rdev regulator driver data   * @rdev: regulator   * @@ -3767,14 +3831,18 @@ static int __init regulator_init_complete(void)  	mutex_lock(®ulator_list_mutex);  	/* If we have a full configuration then disable any regulators -	 * which are not in use or always_on.  This will become the -	 * default behaviour in the future. +	 * we have permission to change the status for and which are +	 * not in use or always_on.  This is effectively the default +	 * for DT and ACPI as they have full constraints.  	 */  	list_for_each_entry(rdev, ®ulator_list, list) {  		ops = rdev->desc->ops;  		c = rdev->constraints; -		if (!ops->disable || (c && c->always_on)) +		if (c && c->always_on) +			continue; + +		if (c && !(c->valid_ops_mask & REGULATOR_CHANGE_STATUS))  			continue;  		mutex_lock(&rdev->mutex); @@ -3791,14 +3859,13 @@ static int __init regulator_init_complete(void)  		if (!enabled)  			goto unlock; -		if (has_full_constraints) { +		if (have_full_constraints()) {  			/* We log since this may kill the system if it  			 * goes wrong. */  			rdev_info(rdev, "disabling\n"); -			ret = ops->disable(rdev); -			if (ret != 0) { +			ret = _regulator_do_disable(rdev); +			if (ret != 0)  				rdev_err(rdev, "couldn't disable: %d\n", ret); -			}  		} else {  			/* The intention is that in future we will  			 * assume that full constraints are provided @@ -3816,4 +3883,4 @@ unlock:  	return 0;  } -late_initcall(regulator_init_complete); +late_initcall_sync(regulator_init_complete);  | 
