diff options
| author | Liam Girdwood <lrg@slimlogic.co.uk> | 2011-08-01 18:25:06 +0100 | 
|---|---|---|
| committer | Liam Girdwood <lrg@slimlogic.co.uk> | 2011-08-01 18:25:06 +0100 | 
| commit | 424c3d4a2c7d4ac3467a4849f8ccc230f670c35a (patch) | |
| tree | 55806b1367b42ec210f273c16bf350182ac6fd62 /drivers/regulator | |
| parent | 02f8c6aee8df3cdc935e9bdd4f2d020306035dbe (diff) | |
| parent | 88cda60e512373ca18a663ee66dc2550800223eb (diff) | |
| download | linux-424c3d4a2c7d4ac3467a4849f8ccc230f670c35a.tar.bz2 | |
Merge branch 'for-next' into for-linus
Diffstat (limited to 'drivers/regulator')
| -rw-r--r-- | drivers/regulator/core.c | 190 | ||||
| -rw-r--r-- | drivers/regulator/dummy.c | 32 | ||||
| -rw-r--r-- | drivers/regulator/tps65910-regulator.c | 63 | ||||
| -rw-r--r-- | drivers/regulator/twl-regulator.c | 66 | ||||
| -rw-r--r-- | drivers/regulator/wm831x-dcdc.c | 126 | ||||
| -rw-r--r-- | drivers/regulator/wm831x-ldo.c | 25 | ||||
| -rw-r--r-- | drivers/regulator/wm8994-regulator.c | 4 | 
7 files changed, 307 insertions, 199 deletions
| diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index d3e38790906e..d8e6a429e8ba 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -20,6 +20,7 @@  #include <linux/debugfs.h>  #include <linux/device.h>  #include <linux/slab.h> +#include <linux/async.h>  #include <linux/err.h>  #include <linux/mutex.h>  #include <linux/suspend.h> @@ -33,6 +34,8 @@  #include "dummy.h" +#define rdev_crit(rdev, fmt, ...)					\ +	pr_crit("%s: " fmt, rdev_get_name(rdev), ##__VA_ARGS__)  #define rdev_err(rdev, fmt, ...)					\  	pr_err("%s: " fmt, rdev_get_name(rdev), ##__VA_ARGS__)  #define rdev_warn(rdev, fmt, ...)					\ @@ -78,11 +81,13 @@ struct regulator {  	char *supply_name;  	struct device_attribute dev_attr;  	struct regulator_dev *rdev; +#ifdef CONFIG_DEBUG_FS +	struct dentry *debugfs; +#endif  };  static int _regulator_is_enabled(struct regulator_dev *rdev); -static int _regulator_disable(struct regulator_dev *rdev, -		struct regulator_dev **supply_rdev_ptr); +static int _regulator_disable(struct regulator_dev *rdev);  static int _regulator_get_voltage(struct regulator_dev *rdev);  static int _regulator_get_current_limit(struct regulator_dev *rdev);  static unsigned int _regulator_get_mode(struct regulator_dev *rdev); @@ -90,6 +95,9 @@ static void _notifier_call_chain(struct regulator_dev *rdev,  				  unsigned long event, void *data);  static int _regulator_do_set_voltage(struct regulator_dev *rdev,  				     int min_uV, int max_uV); +static struct regulator *create_regulator(struct regulator_dev *rdev, +					  struct device *dev, +					  const char *supply_name);  static const char *rdev_get_name(struct regulator_dev *rdev)  { @@ -143,8 +151,11 @@ static int regulator_check_voltage(struct regulator_dev *rdev,  	if (*min_uV < rdev->constraints->min_uV)  		*min_uV = rdev->constraints->min_uV; -	if (*min_uV > *max_uV) +	if (*min_uV > *max_uV) { +		rdev_err(rdev, "unsupportable voltage range: %d-%duV\n", +			 *min_uV, *max_uV);  		return -EINVAL; +	}  	return 0;  } @@ -197,8 +208,11 @@ static int regulator_check_current_limit(struct regulator_dev *rdev,  	if (*min_uA < rdev->constraints->min_uA)  		*min_uA = rdev->constraints->min_uA; -	if (*min_uA > *max_uA) +	if (*min_uA > *max_uA) { +		rdev_err(rdev, "unsupportable current range: %d-%duA\n", +			 *min_uA, *max_uA);  		return -EINVAL; +	}  	return 0;  } @@ -213,6 +227,7 @@ static int regulator_mode_constrain(struct regulator_dev *rdev, int *mode)  	case REGULATOR_MODE_STANDBY:  		break;  	default: +		rdev_err(rdev, "invalid mode %x specified\n", *mode);  		return -EINVAL;  	} @@ -779,7 +794,6 @@ static int machine_constraints_voltage(struct regulator_dev *rdev,  		if (ret < 0) {  			rdev_err(rdev, "failed to apply %duV constraint\n",  				 rdev->constraints->min_uV); -			rdev->constraints = NULL;  			return ret;  		}  	} @@ -882,7 +896,6 @@ static int set_machine_constraints(struct regulator_dev *rdev,  		ret = suspend_prepare(rdev, rdev->constraints->initial_state);  		if (ret < 0) {  			rdev_err(rdev, "failed to set suspend state\n"); -			rdev->constraints = NULL;  			goto out;  		}  	} @@ -909,13 +922,15 @@ static int set_machine_constraints(struct regulator_dev *rdev,  		ret = ops->enable(rdev);  		if (ret < 0) {  			rdev_err(rdev, "failed to enable\n"); -			rdev->constraints = NULL;  			goto out;  		}  	}  	print_constraints(rdev); +	return 0;  out: +	kfree(rdev->constraints); +	rdev->constraints = NULL;  	return ret;  } @@ -929,21 +944,20 @@ out:   * core if it's child is enabled.   */  static int set_supply(struct regulator_dev *rdev, -	struct regulator_dev *supply_rdev) +		      struct regulator_dev *supply_rdev)  {  	int err; -	err = sysfs_create_link(&rdev->dev.kobj, &supply_rdev->dev.kobj, -				"supply"); -	if (err) { -		rdev_err(rdev, "could not add device link %s err %d\n", -			 supply_rdev->dev.kobj.name, err); -		       goto out; +	rdev_info(rdev, "supplied by %s\n", rdev_get_name(supply_rdev)); + +	rdev->supply = create_regulator(supply_rdev, &rdev->dev, "SUPPLY"); +	if (IS_ERR(rdev->supply)) { +		err = PTR_ERR(rdev->supply); +		rdev->supply = NULL; +		return err;  	} -	rdev->supply = supply_rdev; -	list_add(&rdev->slist, &supply_rdev->supply_list); -out: -	return err; + +	return 0;  }  /** @@ -1032,7 +1046,7 @@ static void unset_regulator_supplies(struct regulator_dev *rdev)  	}  } -#define REG_STR_SIZE	32 +#define REG_STR_SIZE	64  static struct regulator *create_regulator(struct regulator_dev *rdev,  					  struct device *dev, @@ -1052,8 +1066,9 @@ static struct regulator *create_regulator(struct regulator_dev *rdev,  	if (dev) {  		/* create a 'requested_microamps_name' sysfs entry */ -		size = scnprintf(buf, REG_STR_SIZE, "microamps_requested_%s", -			supply_name); +		size = scnprintf(buf, REG_STR_SIZE, +				 "microamps_requested_%s-%s", +				 dev_name(dev), supply_name);  		if (size >= REG_STR_SIZE)  			goto overflow_err; @@ -1088,7 +1103,28 @@ static struct regulator *create_regulator(struct regulator_dev *rdev,  				  dev->kobj.name, err);  			goto link_name_err;  		} +	} else { +		regulator->supply_name = kstrdup(supply_name, GFP_KERNEL); +		if (regulator->supply_name == NULL) +			goto attr_err; +	} + +#ifdef CONFIG_DEBUG_FS +	regulator->debugfs = debugfs_create_dir(regulator->supply_name, +						rdev->debugfs); +	if (IS_ERR_OR_NULL(regulator->debugfs)) { +		rdev_warn(rdev, "Failed to create debugfs directory\n"); +		regulator->debugfs = NULL; +	} else { +		debugfs_create_u32("uA_load", 0444, regulator->debugfs, +				   ®ulator->uA_load); +		debugfs_create_u32("min_uV", 0444, regulator->debugfs, +				   ®ulator->min_uV); +		debugfs_create_u32("max_uV", 0444, regulator->debugfs, +				   ®ulator->max_uV);  	} +#endif +  	mutex_unlock(&rdev->mutex);  	return regulator;  link_name_err: @@ -1267,13 +1303,17 @@ void regulator_put(struct regulator *regulator)  	mutex_lock(®ulator_list_mutex);  	rdev = regulator->rdev; +#ifdef CONFIG_DEBUG_FS +	debugfs_remove_recursive(regulator->debugfs); +#endif +  	/* remove any sysfs entries */  	if (regulator->dev) {  		sysfs_remove_link(&rdev->dev.kobj, regulator->supply_name); -		kfree(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); @@ -1301,19 +1341,6 @@ static int _regulator_enable(struct regulator_dev *rdev)  {  	int ret, delay; -	if (rdev->use_count == 0) { -		/* do we need to enable the supply regulator first */ -		if (rdev->supply) { -			mutex_lock(&rdev->supply->mutex); -			ret = _regulator_enable(rdev->supply); -			mutex_unlock(&rdev->supply->mutex); -			if (ret < 0) { -				rdev_err(rdev, "failed to enable: %d\n", ret); -				return ret; -			} -		} -	} -  	/* check voltage and requested load before enabling */  	if (rdev->constraints &&  	    (rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_DRMS)) @@ -1388,19 +1415,27 @@ int regulator_enable(struct regulator *regulator)  	struct regulator_dev *rdev = regulator->rdev;  	int ret = 0; +	if (rdev->supply) { +		ret = regulator_enable(rdev->supply); +		if (ret != 0) +			return ret; +	} +  	mutex_lock(&rdev->mutex);  	ret = _regulator_enable(rdev);  	mutex_unlock(&rdev->mutex); + +	if (ret != 0) +		regulator_disable(rdev->supply); +  	return ret;  }  EXPORT_SYMBOL_GPL(regulator_enable);  /* locks held by regulator_disable() */ -static int _regulator_disable(struct regulator_dev *rdev, -		struct regulator_dev **supply_rdev_ptr) +static int _regulator_disable(struct regulator_dev *rdev)  {  	int ret = 0; -	*supply_rdev_ptr = NULL;  	if (WARN(rdev->use_count <= 0,  		 "unbalanced disables for %s\n", rdev_get_name(rdev))) @@ -1427,9 +1462,6 @@ static int _regulator_disable(struct regulator_dev *rdev,  					     NULL);  		} -		/* decrease our supplies ref count and disable if required */ -		*supply_rdev_ptr = rdev->supply; -  		rdev->use_count = 0;  	} else if (rdev->use_count > 1) { @@ -1440,6 +1472,7 @@ static int _regulator_disable(struct regulator_dev *rdev,  		rdev->use_count--;  	} +  	return ret;  } @@ -1458,29 +1491,21 @@ static int _regulator_disable(struct regulator_dev *rdev,  int regulator_disable(struct regulator *regulator)  {  	struct regulator_dev *rdev = regulator->rdev; -	struct regulator_dev *supply_rdev = NULL;  	int ret = 0;  	mutex_lock(&rdev->mutex); -	ret = _regulator_disable(rdev, &supply_rdev); +	ret = _regulator_disable(rdev);  	mutex_unlock(&rdev->mutex); -	/* decrease our supplies ref count and disable if required */ -	while (supply_rdev != NULL) { -		rdev = supply_rdev; - -		mutex_lock(&rdev->mutex); -		_regulator_disable(rdev, &supply_rdev); -		mutex_unlock(&rdev->mutex); -	} +	if (ret == 0 && rdev->supply) +		regulator_disable(rdev->supply);  	return ret;  }  EXPORT_SYMBOL_GPL(regulator_disable);  /* locks held by regulator_force_disable() */ -static int _regulator_force_disable(struct regulator_dev *rdev, -		struct regulator_dev **supply_rdev_ptr) +static int _regulator_force_disable(struct regulator_dev *rdev)  {  	int ret = 0; @@ -1497,10 +1522,6 @@ static int _regulator_force_disable(struct regulator_dev *rdev,  			REGULATOR_EVENT_DISABLE, NULL);  	} -	/* decrease our supplies ref count and disable if required */ -	*supply_rdev_ptr = rdev->supply; - -	rdev->use_count = 0;  	return ret;  } @@ -1516,16 +1537,16 @@ static int _regulator_force_disable(struct regulator_dev *rdev,  int regulator_force_disable(struct regulator *regulator)  {  	struct regulator_dev *rdev = regulator->rdev; -	struct regulator_dev *supply_rdev = NULL;  	int ret;  	mutex_lock(&rdev->mutex);  	regulator->uA_load = 0; -	ret = _regulator_force_disable(rdev, &supply_rdev); +	ret = _regulator_force_disable(regulator->rdev);  	mutex_unlock(&rdev->mutex); -	if (supply_rdev) -		regulator_disable(get_device_regulator(rdev_get_dev(supply_rdev))); +	if (rdev->supply) +		while (rdev->open_count--) +			regulator_disable(rdev->supply);  	return ret;  } @@ -2136,7 +2157,7 @@ int regulator_set_optimum_mode(struct regulator *regulator, int uA_load)  	/* get input voltage */  	input_uV = 0;  	if (rdev->supply) -		input_uV = _regulator_get_voltage(rdev->supply); +		input_uV = regulator_get_voltage(rdev->supply);  	if (input_uV <= 0)  		input_uV = rdev->constraints->input_uV;  	if (input_uV <= 0) { @@ -2206,17 +2227,8 @@ EXPORT_SYMBOL_GPL(regulator_unregister_notifier);  static void _notifier_call_chain(struct regulator_dev *rdev,  				  unsigned long event, void *data)  { -	struct regulator_dev *_rdev; -  	/* call rdev chain first */  	blocking_notifier_call_chain(&rdev->notifier, event, NULL); - -	/* now notify regulator we supply */ -	list_for_each_entry(_rdev, &rdev->supply_list, slist) { -		mutex_lock(&_rdev->mutex); -		_notifier_call_chain(_rdev, event, data); -		mutex_unlock(&_rdev->mutex); -	}  }  /** @@ -2264,6 +2276,13 @@ err:  }  EXPORT_SYMBOL_GPL(regulator_bulk_get); +static void regulator_bulk_enable_async(void *data, async_cookie_t cookie) +{ +	struct regulator_bulk_data *bulk = data; + +	bulk->ret = regulator_enable(bulk->consumer); +} +  /**   * regulator_bulk_enable - enable multiple regulator consumers   * @@ -2279,21 +2298,33 @@ EXPORT_SYMBOL_GPL(regulator_bulk_get);  int regulator_bulk_enable(int num_consumers,  			  struct regulator_bulk_data *consumers)  { +	LIST_HEAD(async_domain);  	int i; -	int ret; +	int ret = 0; + +	for (i = 0; i < num_consumers; i++) +		async_schedule_domain(regulator_bulk_enable_async, +				      &consumers[i], &async_domain); + +	async_synchronize_full_domain(&async_domain); +	/* If any consumer failed we need to unwind any that succeeded */  	for (i = 0; i < num_consumers; i++) { -		ret = regulator_enable(consumers[i].consumer); -		if (ret != 0) +		if (consumers[i].ret != 0) { +			ret = consumers[i].ret;  			goto err; +		}  	}  	return 0;  err: -	pr_err("Failed to enable %s: %d\n", consumers[i].supply, ret); -	for (--i; i >= 0; --i) -		regulator_disable(consumers[i].consumer); +	for (i = 0; i < num_consumers; i++) +		if (consumers[i].ret == 0) +			regulator_disable(consumers[i].consumer); +		else +			pr_err("Failed to enable %s: %d\n", +			       consumers[i].supply, consumers[i].ret);  	return ret;  } @@ -2589,9 +2620,7 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc,  	rdev->owner = regulator_desc->owner;  	rdev->desc = regulator_desc;  	INIT_LIST_HEAD(&rdev->consumer_list); -	INIT_LIST_HEAD(&rdev->supply_list);  	INIT_LIST_HEAD(&rdev->list); -	INIT_LIST_HEAD(&rdev->slist);  	BLOCKING_INIT_NOTIFIER_HEAD(&rdev->notifier);  	/* preform any regulator specific init */ @@ -2672,6 +2701,7 @@ unset_supplies:  	unset_regulator_supplies(rdev);  scrub: +	kfree(rdev->constraints);  	device_unregister(&rdev->dev);  	/* device core frees rdev */  	rdev = ERR_PTR(ret); @@ -2703,7 +2733,7 @@ void regulator_unregister(struct regulator_dev *rdev)  	unset_regulator_supplies(rdev);  	list_del(&rdev->list);  	if (rdev->supply) -		sysfs_remove_link(&rdev->dev.kobj, "supply"); +		regulator_put(rdev->supply);  	device_unregister(&rdev->dev);  	kfree(rdev->constraints);  	mutex_unlock(®ulator_list_mutex); diff --git a/drivers/regulator/dummy.c b/drivers/regulator/dummy.c index c7410bde7b5d..f6ef6694ab98 100644 --- a/drivers/regulator/dummy.c +++ b/drivers/regulator/dummy.c @@ -36,6 +36,29 @@ static struct regulator_desc dummy_desc = {  	.ops = &dummy_ops,  }; +static int __devinit dummy_regulator_probe(struct platform_device *pdev) +{ +	int ret; + +	dummy_regulator_rdev = regulator_register(&dummy_desc, NULL, +						  &dummy_initdata, NULL); +	if (IS_ERR(dummy_regulator_rdev)) { +		ret = PTR_ERR(dummy_regulator_rdev); +		pr_err("Failed to register regulator: %d\n", ret); +		return ret; +	} + +	return 0; +} + +static struct platform_driver dummy_regulator_driver = { +	.probe		= dummy_regulator_probe, +	.driver		= { +		.name		= "reg-dummy", +		.owner		= THIS_MODULE, +	}, +}; +  static struct platform_device *dummy_pdev;  void __init regulator_dummy_init(void) @@ -55,12 +78,9 @@ void __init regulator_dummy_init(void)  		return;  	} -	dummy_regulator_rdev = regulator_register(&dummy_desc, NULL, -						  &dummy_initdata, NULL); -	if (IS_ERR(dummy_regulator_rdev)) { -		ret = PTR_ERR(dummy_regulator_rdev); -		pr_err("Failed to register regulator: %d\n", ret); +	ret = platform_driver_register(&dummy_regulator_driver); +	if (ret != 0) { +		pr_err("Failed to register dummy regulator driver: %d\n", ret);  		platform_device_unregister(dummy_pdev); -		return;  	}  } diff --git a/drivers/regulator/tps65910-regulator.c b/drivers/regulator/tps65910-regulator.c index 55dd4e6650db..66d2d60b436a 100644 --- a/drivers/regulator/tps65910-regulator.c +++ b/drivers/regulator/tps65910-regulator.c @@ -49,7 +49,6 @@  #define TPS65911_REG_LDO7		11  #define TPS65911_REG_LDO8		12 -#define TPS65910_NUM_REGULATOR		13  #define TPS65910_SUPPLY_STATE_ENABLED	0x1  /* supported VIO voltages in milivolts */ @@ -264,11 +263,12 @@ static struct tps_info tps65911_regs[] = {  };  struct tps65910_reg { -	struct regulator_desc desc[TPS65910_NUM_REGULATOR]; +	struct regulator_desc *desc;  	struct tps65910 *mfd; -	struct regulator_dev *rdev[TPS65910_NUM_REGULATOR]; -	struct tps_info *info[TPS65910_NUM_REGULATOR]; +	struct regulator_dev **rdev; +	struct tps_info **info;  	struct mutex mutex; +	int num_regulators;  	int mode;  	int  (*get_ctrl_reg)(int);  }; @@ -759,8 +759,13 @@ static int tps65910_list_voltage_dcdc(struct regulator_dev *dev,  		mult = (selector / VDD1_2_NUM_VOLTS) + 1;  		volt = VDD1_2_MIN_VOLT +  				(selector % VDD1_2_NUM_VOLTS) * VDD1_2_OFFSET; +		break;  	case TPS65911_REG_VDDCTRL:  		volt = VDDCTRL_MIN_VOLT + (selector * VDDCTRL_OFFSET); +		break; +	default: +		BUG(); +		return -EINVAL;  	}  	return  volt * 100 * mult; @@ -897,16 +902,42 @@ static __devinit int tps65910_probe(struct platform_device *pdev)  	switch(tps65910_chip_id(tps65910)) {  	case TPS65910:  		pmic->get_ctrl_reg = &tps65910_get_ctrl_register; +		pmic->num_regulators = ARRAY_SIZE(tps65910_regs);  		info = tps65910_regs; +		break;  	case TPS65911:  		pmic->get_ctrl_reg = &tps65911_get_ctrl_register; +		pmic->num_regulators = ARRAY_SIZE(tps65911_regs);  		info = tps65911_regs; +		break;  	default:  		pr_err("Invalid tps chip version\n"); +		kfree(pmic);  		return -ENODEV;  	} -	for (i = 0; i < TPS65910_NUM_REGULATOR; i++, info++, reg_data++) { +	pmic->desc = kcalloc(pmic->num_regulators, +			sizeof(struct regulator_desc), GFP_KERNEL); +	if (!pmic->desc) { +		err = -ENOMEM; +		goto err_free_pmic; +	} + +	pmic->info = kcalloc(pmic->num_regulators, +			sizeof(struct tps_info *), GFP_KERNEL); +	if (!pmic->info) { +		err = -ENOMEM; +		goto err_free_desc; +	} + +	pmic->rdev = kcalloc(pmic->num_regulators, +			sizeof(struct regulator_dev *), GFP_KERNEL); +	if (!pmic->rdev) { +		err = -ENOMEM; +		goto err_free_info; +	} + +	for (i = 0; i < pmic->num_regulators; i++, info++, reg_data++) {  		/* Register the regulators */  		pmic->info[i] = info; @@ -938,7 +969,7 @@ static __devinit int tps65910_probe(struct platform_device *pdev)  				"failed to register %s regulator\n",  				pdev->name);  			err = PTR_ERR(rdev); -			goto err; +			goto err_unregister_regulator;  		}  		/* Save regulator for cleanup */ @@ -946,23 +977,31 @@ static __devinit int tps65910_probe(struct platform_device *pdev)  	}  	return 0; -err: +err_unregister_regulator:  	while (--i >= 0)  		regulator_unregister(pmic->rdev[i]); - +	kfree(pmic->rdev); +err_free_info: +	kfree(pmic->info); +err_free_desc: +	kfree(pmic->desc); +err_free_pmic:  	kfree(pmic);  	return err;  }  static int __devexit tps65910_remove(struct platform_device *pdev)  { -	struct tps65910_reg *tps65910_reg = platform_get_drvdata(pdev); +	struct tps65910_reg *pmic = platform_get_drvdata(pdev);  	int i; -	for (i = 0; i < TPS65910_NUM_REGULATOR; i++) -		regulator_unregister(tps65910_reg->rdev[i]); +	for (i = 0; i < pmic->num_regulators; i++) +		regulator_unregister(pmic->rdev[i]); -	kfree(tps65910_reg); +	kfree(pmic->rdev); +	kfree(pmic->info); +	kfree(pmic->desc); +	kfree(pmic);  	return 0;  } diff --git a/drivers/regulator/twl-regulator.c b/drivers/regulator/twl-regulator.c index 87fe0f75a56e..ee8747f4fa08 100644 --- a/drivers/regulator/twl-regulator.c +++ b/drivers/regulator/twl-regulator.c @@ -835,8 +835,8 @@ static struct regulator_ops twlsmps_ops = {  			remap_conf) \  		TWL_FIXED_LDO(label, offset, mVolts, num, turnon_delay, \  			remap_conf, TWL4030, twl4030fixed_ops) -#define TWL6030_FIXED_LDO(label, offset, mVolts, num, turnon_delay) \ -		TWL_FIXED_LDO(label, offset, mVolts, num, turnon_delay, \ +#define TWL6030_FIXED_LDO(label, offset, mVolts, turnon_delay) \ +		TWL_FIXED_LDO(label, offset, mVolts, 0x0, turnon_delay, \  			0x0, TWL6030, twl6030fixed_ops)  #define TWL4030_ADJUSTABLE_LDO(label, offset, num, turnon_delay, remap_conf) { \ @@ -856,24 +856,22 @@ static struct regulator_ops twlsmps_ops = {  		}, \  	} -#define TWL6030_ADJUSTABLE_LDO(label, offset, min_mVolts, max_mVolts, num) { \ +#define TWL6030_ADJUSTABLE_LDO(label, offset, min_mVolts, max_mVolts) { \  	.base = offset, \ -	.id = num, \  	.min_mV = min_mVolts, \  	.max_mV = max_mVolts, \  	.desc = { \  		.name = #label, \  		.id = TWL6030_REG_##label, \ -		.n_voltages = (max_mVolts - min_mVolts)/100, \ +		.n_voltages = (max_mVolts - min_mVolts)/100 + 1, \  		.ops = &twl6030ldo_ops, \  		.type = REGULATOR_VOLTAGE, \  		.owner = THIS_MODULE, \  		}, \  	} -#define TWL6025_ADJUSTABLE_LDO(label, offset, min_mVolts, max_mVolts, num) { \ +#define TWL6025_ADJUSTABLE_LDO(label, offset, min_mVolts, max_mVolts) { \  	.base = offset, \ -	.id = num, \  	.min_mV = min_mVolts, \  	.max_mV = max_mVolts, \  	.desc = { \ @@ -903,9 +901,8 @@ static struct regulator_ops twlsmps_ops = {  		}, \  	} -#define TWL6030_FIXED_RESOURCE(label, offset, num, turnon_delay) { \ +#define TWL6030_FIXED_RESOURCE(label, offset, turnon_delay) { \  	.base = offset, \ -	.id = num, \  	.delay = turnon_delay, \  	.desc = { \  		.name = #label, \ @@ -916,9 +913,8 @@ static struct regulator_ops twlsmps_ops = {  		}, \  	} -#define TWL6025_ADJUSTABLE_SMPS(label, offset, num) { \ +#define TWL6025_ADJUSTABLE_SMPS(label, offset) { \  	.base = offset, \ -	.id = num, \  	.min_mV = 600, \  	.max_mV = 2100, \  	.desc = { \ @@ -961,32 +957,32 @@ static struct twlreg_info twl_regs[] = {  	/* 6030 REG with base as PMC Slave Misc : 0x0030 */  	/* Turnon-delay and remap configuration values for 6030 are not  	   verified since the specification is not public */ -	TWL6030_ADJUSTABLE_LDO(VAUX1_6030, 0x54, 1000, 3300, 1), -	TWL6030_ADJUSTABLE_LDO(VAUX2_6030, 0x58, 1000, 3300, 2), -	TWL6030_ADJUSTABLE_LDO(VAUX3_6030, 0x5c, 1000, 3300, 3), -	TWL6030_ADJUSTABLE_LDO(VMMC, 0x68, 1000, 3300, 4), -	TWL6030_ADJUSTABLE_LDO(VPP, 0x6c, 1000, 3300, 5), -	TWL6030_ADJUSTABLE_LDO(VUSIM, 0x74, 1000, 3300, 7), -	TWL6030_FIXED_LDO(VANA, 0x50, 2100, 15, 0), -	TWL6030_FIXED_LDO(VCXIO, 0x60, 1800, 16, 0), -	TWL6030_FIXED_LDO(VDAC, 0x64, 1800, 17, 0), -	TWL6030_FIXED_LDO(VUSB, 0x70, 3300, 18, 0), -	TWL6030_FIXED_RESOURCE(CLK32KG, 0x8C, 48, 0), +	TWL6030_ADJUSTABLE_LDO(VAUX1_6030, 0x54, 1000, 3300), +	TWL6030_ADJUSTABLE_LDO(VAUX2_6030, 0x58, 1000, 3300), +	TWL6030_ADJUSTABLE_LDO(VAUX3_6030, 0x5c, 1000, 3300), +	TWL6030_ADJUSTABLE_LDO(VMMC, 0x68, 1000, 3300), +	TWL6030_ADJUSTABLE_LDO(VPP, 0x6c, 1000, 3300), +	TWL6030_ADJUSTABLE_LDO(VUSIM, 0x74, 1000, 3300), +	TWL6030_FIXED_LDO(VANA, 0x50, 2100, 0), +	TWL6030_FIXED_LDO(VCXIO, 0x60, 1800, 0), +	TWL6030_FIXED_LDO(VDAC, 0x64, 1800, 0), +	TWL6030_FIXED_LDO(VUSB, 0x70, 3300, 0), +	TWL6030_FIXED_RESOURCE(CLK32KG, 0x8C, 0),  	/* 6025 are renamed compared to 6030 versions */ -	TWL6025_ADJUSTABLE_LDO(LDO2, 0x54, 1000, 3300, 1), -	TWL6025_ADJUSTABLE_LDO(LDO4, 0x58, 1000, 3300, 2), -	TWL6025_ADJUSTABLE_LDO(LDO3, 0x5c, 1000, 3300, 3), -	TWL6025_ADJUSTABLE_LDO(LDO5, 0x68, 1000, 3300, 4), -	TWL6025_ADJUSTABLE_LDO(LDO1, 0x6c, 1000, 3300, 5), -	TWL6025_ADJUSTABLE_LDO(LDO7, 0x74, 1000, 3300, 7), -	TWL6025_ADJUSTABLE_LDO(LDO6, 0x60, 1000, 3300, 16), -	TWL6025_ADJUSTABLE_LDO(LDOLN, 0x64, 1000, 3300, 17), -	TWL6025_ADJUSTABLE_LDO(LDOUSB, 0x70, 1000, 3300, 18), - -	TWL6025_ADJUSTABLE_SMPS(SMPS3, 0x34, 1), -	TWL6025_ADJUSTABLE_SMPS(SMPS4, 0x10, 2), -	TWL6025_ADJUSTABLE_SMPS(VIO, 0x16, 3), +	TWL6025_ADJUSTABLE_LDO(LDO2, 0x54, 1000, 3300), +	TWL6025_ADJUSTABLE_LDO(LDO4, 0x58, 1000, 3300), +	TWL6025_ADJUSTABLE_LDO(LDO3, 0x5c, 1000, 3300), +	TWL6025_ADJUSTABLE_LDO(LDO5, 0x68, 1000, 3300), +	TWL6025_ADJUSTABLE_LDO(LDO1, 0x6c, 1000, 3300), +	TWL6025_ADJUSTABLE_LDO(LDO7, 0x74, 1000, 3300), +	TWL6025_ADJUSTABLE_LDO(LDO6, 0x60, 1000, 3300), +	TWL6025_ADJUSTABLE_LDO(LDOLN, 0x64, 1000, 3300), +	TWL6025_ADJUSTABLE_LDO(LDOUSB, 0x70, 1000, 3300), + +	TWL6025_ADJUSTABLE_SMPS(SMPS3, 0x34), +	TWL6025_ADJUSTABLE_SMPS(SMPS4, 0x10), +	TWL6025_ADJUSTABLE_SMPS(VIO, 0x16),  };  static u8 twl_get_smps_offset(void) diff --git a/drivers/regulator/wm831x-dcdc.c b/drivers/regulator/wm831x-dcdc.c index a0982e809851..bd3531d8b2ac 100644 --- a/drivers/regulator/wm831x-dcdc.c +++ b/drivers/regulator/wm831x-dcdc.c @@ -267,23 +267,6 @@ static int wm831x_buckv_select_min_voltage(struct regulator_dev *rdev,  	return vsel;  } -static int wm831x_buckv_select_max_voltage(struct regulator_dev *rdev, -					   int min_uV, int max_uV) -{ -	u16 vsel; - -	if (max_uV < 600000 || max_uV > 1800000) -		return -EINVAL; - -	vsel = ((max_uV - 600000) / 12500) + 8; - -	if (wm831x_buckv_list_voltage(rdev, vsel) < min_uV || -	    wm831x_buckv_list_voltage(rdev, vsel) < max_uV) -		return -EINVAL; - -	return vsel; -} -  static int wm831x_buckv_set_dvs(struct regulator_dev *rdev, int state)  {  	struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev); @@ -338,28 +321,23 @@ static int wm831x_buckv_set_voltage(struct regulator_dev *rdev,  	if (ret < 0)  		return ret; -	/* Set the high voltage as the DVS voltage.  This is optimised -	 * for CPUfreq usage, most processors will keep the maximum -	 * voltage constant and lower the minimum with the frequency. */ -	vsel = wm831x_buckv_select_max_voltage(rdev, min_uV, max_uV); -	if (vsel < 0) { -		/* This should never happen - at worst the same vsel -		 * should be chosen */ -		WARN_ON(vsel < 0); -		return 0; +	/* +	 * If this VSEL is higher than the last one we've seen then +	 * remember it as the DVS VSEL.  This is optimised for CPUfreq +	 * usage where we want to get to the highest voltage very +	 * quickly. +	 */ +	if (vsel > dcdc->dvs_vsel) { +		ret = wm831x_set_bits(wm831x, dvs_reg, +				      WM831X_DC1_DVS_VSEL_MASK, +				      dcdc->dvs_vsel); +		if (ret == 0) +			dcdc->dvs_vsel = vsel; +		else +			dev_warn(wm831x->dev, +				 "Failed to set DCDC DVS VSEL: %d\n", ret);  	} -	/* Don't bother if it's the same VSEL we're already using */ -	if (vsel == dcdc->on_vsel) -		return 0; - -	ret = wm831x_set_bits(wm831x, dvs_reg, WM831X_DC1_DVS_VSEL_MASK, vsel); -	if (ret == 0) -		dcdc->dvs_vsel = vsel; -	else -		dev_warn(wm831x->dev, "Failed to set DCDC DVS VSEL: %d\n", -			 ret); -  	return 0;  } @@ -456,27 +434,6 @@ static __devinit void wm831x_buckv_dvs_init(struct wm831x_dcdc *dcdc,  	if (!pdata || !pdata->dvs_gpio)  		return; -	switch (pdata->dvs_control_src) { -	case 1: -		ctrl = 2 << WM831X_DC1_DVS_SRC_SHIFT; -		break; -	case 2: -		ctrl = 3 << WM831X_DC1_DVS_SRC_SHIFT; -		break; -	default: -		dev_err(wm831x->dev, "Invalid DVS control source %d for %s\n", -			pdata->dvs_control_src, dcdc->name); -		return; -	} - -	ret = wm831x_set_bits(wm831x, dcdc->base + WM831X_DCDC_DVS_CONTROL, -			      WM831X_DC1_DVS_SRC_MASK, ctrl); -	if (ret < 0) { -		dev_err(wm831x->dev, "Failed to set %s DVS source: %d\n", -			dcdc->name, ret); -		return; -	} -  	ret = gpio_request(pdata->dvs_gpio, "DCDC DVS");  	if (ret < 0) {  		dev_err(wm831x->dev, "Failed to get %s DVS GPIO: %d\n", @@ -498,17 +455,57 @@ static __devinit void wm831x_buckv_dvs_init(struct wm831x_dcdc *dcdc,  	}  	dcdc->dvs_gpio = pdata->dvs_gpio; + +	switch (pdata->dvs_control_src) { +	case 1: +		ctrl = 2 << WM831X_DC1_DVS_SRC_SHIFT; +		break; +	case 2: +		ctrl = 3 << WM831X_DC1_DVS_SRC_SHIFT; +		break; +	default: +		dev_err(wm831x->dev, "Invalid DVS control source %d for %s\n", +			pdata->dvs_control_src, dcdc->name); +		return; +	} + +	/* If DVS_VSEL is set to the minimum value then raise it to ON_VSEL +	 * to make bootstrapping a bit smoother. +	 */ +	if (!dcdc->dvs_vsel) { +		ret = wm831x_set_bits(wm831x, +				      dcdc->base + WM831X_DCDC_DVS_CONTROL, +				      WM831X_DC1_DVS_VSEL_MASK, dcdc->on_vsel); +		if (ret == 0) +			dcdc->dvs_vsel = dcdc->on_vsel; +		else +			dev_warn(wm831x->dev, "Failed to set DVS_VSEL: %d\n", +				 ret); +	} + +	ret = wm831x_set_bits(wm831x, dcdc->base + WM831X_DCDC_DVS_CONTROL, +			      WM831X_DC1_DVS_SRC_MASK, ctrl); +	if (ret < 0) { +		dev_err(wm831x->dev, "Failed to set %s DVS source: %d\n", +			dcdc->name, ret); +	}  }  static __devinit int wm831x_buckv_probe(struct platform_device *pdev)  {  	struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);  	struct wm831x_pdata *pdata = wm831x->dev->platform_data; -	int id = pdev->id % ARRAY_SIZE(pdata->dcdc); +	int id;  	struct wm831x_dcdc *dcdc;  	struct resource *res;  	int ret, irq; +	if (pdata && pdata->wm831x_num) +		id = (pdata->wm831x_num * 10) + 1; +	else +		id = 0; +	id = pdev->id - id; +  	dev_dbg(&pdev->dev, "Probing DCDC%d\n", id + 1);  	if (pdata == NULL || pdata->dcdc[id] == NULL) @@ -545,7 +542,7 @@ static __devinit int wm831x_buckv_probe(struct platform_device *pdev)  	}  	dcdc->on_vsel = ret & WM831X_DC1_ON_VSEL_MASK; -	ret = wm831x_reg_read(wm831x, dcdc->base + WM831X_DCDC_ON_CONFIG); +	ret = wm831x_reg_read(wm831x, dcdc->base + WM831X_DCDC_DVS_CONTROL);  	if (ret < 0) {  		dev_err(wm831x->dev, "Failed to read DVS VSEL: %d\n", ret);  		goto err; @@ -709,11 +706,17 @@ static __devinit int wm831x_buckp_probe(struct platform_device *pdev)  {  	struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);  	struct wm831x_pdata *pdata = wm831x->dev->platform_data; -	int id = pdev->id % ARRAY_SIZE(pdata->dcdc); +	int id;  	struct wm831x_dcdc *dcdc;  	struct resource *res;  	int ret, irq; +	if (pdata && pdata->wm831x_num) +		id = (pdata->wm831x_num * 10) + 1; +	else +		id = 0; +	id = pdev->id - id; +  	dev_dbg(&pdev->dev, "Probing DCDC%d\n", id + 1);  	if (pdata == NULL || pdata->dcdc[id] == NULL) @@ -1046,3 +1049,4 @@ MODULE_DESCRIPTION("WM831x DC-DC convertor driver");  MODULE_LICENSE("GPL");  MODULE_ALIAS("platform:wm831x-buckv");  MODULE_ALIAS("platform:wm831x-buckp"); +MODULE_ALIAS("platform:wm831x-epe"); diff --git a/drivers/regulator/wm831x-ldo.c b/drivers/regulator/wm831x-ldo.c index 2220cf8defb1..6709710a059e 100644 --- a/drivers/regulator/wm831x-ldo.c +++ b/drivers/regulator/wm831x-ldo.c @@ -310,11 +310,17 @@ static __devinit int wm831x_gp_ldo_probe(struct platform_device *pdev)  {  	struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);  	struct wm831x_pdata *pdata = wm831x->dev->platform_data; -	int id = pdev->id % ARRAY_SIZE(pdata->ldo); +	int id;  	struct wm831x_ldo *ldo;  	struct resource *res;  	int ret, irq; +	if (pdata && pdata->wm831x_num) +		id = (pdata->wm831x_num * 10) + 1; +	else +		id = 0; +	id = pdev->id - id; +  	dev_dbg(&pdev->dev, "Probing LDO%d\n", id + 1);  	if (pdata == NULL || pdata->ldo[id] == NULL) @@ -574,11 +580,17 @@ static __devinit int wm831x_aldo_probe(struct platform_device *pdev)  {  	struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);  	struct wm831x_pdata *pdata = wm831x->dev->platform_data; -	int id = pdev->id % ARRAY_SIZE(pdata->ldo); +	int id;  	struct wm831x_ldo *ldo;  	struct resource *res;  	int ret, irq; +	if (pdata && pdata->wm831x_num) +		id = (pdata->wm831x_num * 10) + 1; +	else +		id = 0; +	id = pdev->id - id; +  	dev_dbg(&pdev->dev, "Probing LDO%d\n", id + 1);  	if (pdata == NULL || pdata->ldo[id] == NULL) @@ -764,11 +776,18 @@ static __devinit int wm831x_alive_ldo_probe(struct platform_device *pdev)  {  	struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);  	struct wm831x_pdata *pdata = wm831x->dev->platform_data; -	int id = pdev->id % ARRAY_SIZE(pdata->ldo); +	int id;  	struct wm831x_ldo *ldo;  	struct resource *res;  	int ret; +	if (pdata && pdata->wm831x_num) +		id = (pdata->wm831x_num * 10) + 1; +	else +		id = 0; +	id = pdev->id - id; + +  	dev_dbg(&pdev->dev, "Probing LDO%d\n", id + 1);  	if (pdata == NULL || pdata->ldo[id] == NULL) diff --git a/drivers/regulator/wm8994-regulator.c b/drivers/regulator/wm8994-regulator.c index 35b2958d5106..1a6a690f24db 100644 --- a/drivers/regulator/wm8994-regulator.c +++ b/drivers/regulator/wm8994-regulator.c @@ -43,7 +43,7 @@ static int wm8994_ldo_enable(struct regulator_dev *rdev)  	if (!ldo->enable)  		return 0; -	gpio_set_value(ldo->enable, 1); +	gpio_set_value_cansleep(ldo->enable, 1);  	ldo->is_enabled = true;  	return 0; @@ -57,7 +57,7 @@ static int wm8994_ldo_disable(struct regulator_dev *rdev)  	if (!ldo->enable)  		return -EINVAL; -	gpio_set_value(ldo->enable, 0); +	gpio_set_value_cansleep(ldo->enable, 0);  	ldo->is_enabled = false;  	return 0; |