diff options
Diffstat (limited to 'drivers/regulator/core.c')
| -rw-r--r-- | drivers/regulator/core.c | 58 | 
1 files changed, 42 insertions, 16 deletions
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index e0c0cf462004..afe94470b67f 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -381,12 +381,16 @@ static struct device_node *of_get_child_regulator(struct device_node *parent,  		if (!regnode) {  			regnode = of_get_child_regulator(child, prop_name);  			if (regnode) -				return regnode; +				goto err_node_put;  		} else { -			return regnode; +			goto err_node_put;  		}  	}  	return NULL; + +err_node_put: +	of_node_put(child); +	return regnode;  }  /** @@ -564,13 +568,15 @@ static ssize_t regulator_uV_show(struct device *dev,  				struct device_attribute *attr, char *buf)  {  	struct regulator_dev *rdev = dev_get_drvdata(dev); -	ssize_t ret; +	int uV;  	regulator_lock(rdev); -	ret = sprintf(buf, "%d\n", regulator_get_voltage_rdev(rdev)); +	uV = regulator_get_voltage_rdev(rdev);  	regulator_unlock(rdev); -	return ret; +	if (uV < 0) +		return uV; +	return sprintf(buf, "%d\n", uV);  }  static DEVICE_ATTR(microvolts, 0444, regulator_uV_show, NULL); @@ -5640,7 +5646,7 @@ static int __init regulator_init(void)  /* init early to allow our consumers to complete system booting */  core_initcall(regulator_init); -static int __init regulator_late_cleanup(struct device *dev, void *data) +static int regulator_late_cleanup(struct device *dev, void *data)  {  	struct regulator_dev *rdev = dev_to_rdev(dev);  	const struct regulator_ops *ops = rdev->desc->ops; @@ -5689,18 +5695,9 @@ unlock:  	return 0;  } -static int __init regulator_init_complete(void) +static void regulator_init_complete_work_function(struct work_struct *work)  {  	/* -	 * 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; - -	/*  	 * Regulators may had failed to resolve their input supplies  	 * when were registered, either because the input supply was  	 * not registered yet or because its parent device was not @@ -5717,6 +5714,35 @@ static int __init regulator_init_complete(void)  	 */  	class_for_each_device(®ulator_class, NULL, NULL,  			      regulator_late_cleanup); +} + +static DECLARE_DELAYED_WORK(regulator_init_complete_work, +			    regulator_init_complete_work_function); + +static int __init regulator_init_complete(void) +{ +	/* +	 * 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; + +	/* +	 * We punt completion for an arbitrary amount of time since +	 * systems like distros will load many drivers from userspace +	 * so consumers might not always be ready yet, this is +	 * particularly an issue with laptops where this might bounce +	 * the display off then on.  Ideally we'd get a notification +	 * from userspace when this happens but we don't so just wait +	 * a bit and hope we waited long enough.  It'd be better if +	 * we'd only do this on systems that need it, and a kernel +	 * command line option might be useful. +	 */ +	schedule_delayed_work(®ulator_init_complete_work, +			      msecs_to_jiffies(30000));  	return 0;  }  |