diff options
28 files changed, 1622 insertions, 184 deletions
| diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 262f62eec837..834b48441829 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -27,6 +27,17 @@ config REGULATOR_DEBUG  	help  	  Say yes here to enable debugging support. +config REGULATOR_DUMMY +	bool "Provide a dummy regulator if regulator lookups fail" +	help +	  If this option is enabled then when a regulator lookup fails +	  and the board has not specified that it has provided full +	  constraints then the regulator core will provide an always +	  enabled dummy regulator will be provided, allowing consumer +	  drivers to continue. + +	  A warning will be generated when this substitution is done. +  config REGULATOR_FIXED_VOLTAGE  	tristate "Fixed voltage regulator support"  	help @@ -69,6 +80,13 @@ config REGULATOR_MAX1586  	  regulator via I2C bus. The provided regulator is suitable  	  for PXA27x chips to control VCC_CORE and VCC_USIM voltages. +config REGULATOR_MAX8649 +	tristate "Maxim 8649 voltage regulator" +	depends on I2C +	help +	  This driver controls a Maxim 8649 voltage output regulator via +	  I2C bus. +  config REGULATOR_MAX8660  	tristate "Maxim 8660/8661 voltage regulator"  	depends on I2C @@ -91,19 +109,26 @@ config REGULATOR_WM831X  	  of PMIC devices.  config REGULATOR_WM8350 -	tristate "Wolfson Microelectroncis WM8350 AudioPlus PMIC" +	tristate "Wolfson Microelectronics WM8350 AudioPlus PMIC"  	depends on MFD_WM8350  	help  	  This driver provides support for the voltage and current regulators            of the WM8350 AudioPlus PMIC.  config REGULATOR_WM8400 -	tristate "Wolfson Microelectroncis WM8400 AudioPlus PMIC" +	tristate "Wolfson Microelectronics WM8400 AudioPlus PMIC"  	depends on MFD_WM8400  	help  	  This driver provides support for the voltage regulators of the  	  WM8400 AudioPlus PMIC. +config REGULATOR_WM8994 +	tristate "Wolfson Microelectronics WM8994 CODEC" +	depends on MFD_WM8994 +	help +	  This driver provides support for the voltage regulators on the +	  WM8994 CODEC. +  config REGULATOR_DA903X  	tristate "Support regulators on Dialog Semiconductor DA9030/DA9034 PMIC"  	depends on PMIC_DA903X diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index b3c806c79415..e845b66ad59c 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -9,15 +9,18 @@ obj-$(CONFIG_REGULATOR_VIRTUAL_CONSUMER) += virtual.o  obj-$(CONFIG_REGULATOR_USERSPACE_CONSUMER) += userspace-consumer.o  obj-$(CONFIG_REGULATOR_BQ24022) += bq24022.o +obj-$(CONFIG_REGULATOR_DUMMY) += dummy.o  obj-$(CONFIG_REGULATOR_LP3971) += lp3971.o  obj-$(CONFIG_REGULATOR_MAX1586) += max1586.o  obj-$(CONFIG_REGULATOR_TWL4030) += twl-regulator.o +obj-$(CONFIG_REGULATOR_MAX8649)	+= max8649.o  obj-$(CONFIG_REGULATOR_MAX8660) += max8660.o  obj-$(CONFIG_REGULATOR_WM831X) += wm831x-dcdc.o  obj-$(CONFIG_REGULATOR_WM831X) += wm831x-isink.o  obj-$(CONFIG_REGULATOR_WM831X) += wm831x-ldo.o  obj-$(CONFIG_REGULATOR_WM8350) += wm8350-regulator.o  obj-$(CONFIG_REGULATOR_WM8400) += wm8400-regulator.o +obj-$(CONFIG_REGULATOR_WM8994) += wm8994-regulator.o  obj-$(CONFIG_REGULATOR_DA903X)	+= da903x.o  obj-$(CONFIG_REGULATOR_PCF50633) += pcf50633-regulator.o  obj-$(CONFIG_REGULATOR_PCAP) += pcap-regulator.o diff --git a/drivers/regulator/ab3100.c b/drivers/regulator/ab3100.c index b349db4504b7..7de950959ed2 100644 --- a/drivers/regulator/ab3100.c +++ b/drivers/regulator/ab3100.c @@ -561,7 +561,7 @@ ab3100_regulator_desc[AB3100_NUM_REGULATORS] = {   * for all the different regulators.   */ -static int __init ab3100_regulators_probe(struct platform_device *pdev) +static int __devinit ab3100_regulators_probe(struct platform_device *pdev)  {  	struct ab3100_platform_data *plfdata = pdev->dev.platform_data;  	struct ab3100 *ab3100 = platform_get_drvdata(pdev); @@ -641,7 +641,7 @@ static int __init ab3100_regulators_probe(struct platform_device *pdev)  	return 0;  } -static int __exit ab3100_regulators_remove(struct platform_device *pdev) +static int __devexit ab3100_regulators_remove(struct platform_device *pdev)  {  	int i; @@ -659,7 +659,7 @@ static struct platform_driver ab3100_regulators_driver = {  		.owner = THIS_MODULE,  	},  	.probe = ab3100_regulators_probe, -	.remove = __exit_p(ab3100_regulators_remove), +	.remove = __devexit_p(ab3100_regulators_remove),  };  static __init int ab3100_regulators_init(void) diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index b60a4c9f8f16..c7bbe30010f7 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -19,10 +19,13 @@  #include <linux/err.h>  #include <linux/mutex.h>  #include <linux/suspend.h> +#include <linux/delay.h>  #include <linux/regulator/consumer.h>  #include <linux/regulator/driver.h>  #include <linux/regulator/machine.h> +#include "dummy.h" +  #define REGULATOR_VERSION "0.5"  static DEFINE_MUTEX(regulator_list_mutex); @@ -1084,6 +1087,13 @@ overflow_err:  	return NULL;  } +static int _regulator_get_enable_time(struct regulator_dev *rdev) +{ +	if (!rdev->desc->ops->enable_time) +		return 0; +	return rdev->desc->ops->enable_time(rdev); +} +  /* Internal regulator request function */  static struct regulator *_regulator_get(struct device *dev, const char *id,  					int exclusive) @@ -1115,6 +1125,22 @@ static struct regulator *_regulator_get(struct device *dev, const char *id,  			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. +	 */ +	if (!has_full_constraints) { +		pr_warning("%s supply %s not found, using dummy regulator\n", +			   devname, id); +		rdev = dummy_regulator_rdev; +		goto found; +	} +#endif +  	mutex_unlock(®ulator_list_mutex);  	return regulator; @@ -1251,7 +1277,7 @@ static int _regulator_can_change_status(struct regulator_dev *rdev)  /* locks held by regulator_enable() */  static int _regulator_enable(struct regulator_dev *rdev)  { -	int ret; +	int ret, delay;  	/* do we need to enable the supply regulator first */  	if (rdev->supply) { @@ -1275,13 +1301,34 @@ static int _regulator_enable(struct regulator_dev *rdev)  			if (!_regulator_can_change_status(rdev))  				return -EPERM; -			if (rdev->desc->ops->enable) { -				ret = rdev->desc->ops->enable(rdev); -				if (ret < 0) -					return ret; -			} else { +			if (!rdev->desc->ops->enable)  				return -EINVAL; + +			/* Query before enabling in case configuration +			 * dependant.  */ +			ret = _regulator_get_enable_time(rdev); +			if (ret >= 0) { +				delay = ret; +			} else { +				printk(KERN_WARNING +					"%s: enable_time() failed for %s: %d\n", +					__func__, rdev_get_name(rdev), +					ret); +				delay = 0;  			} + +			/* Allow the regulator to ramp; it would be useful +			 * to extend this for bulk operations so that the +			 * regulators can ramp together.  */ +			ret = rdev->desc->ops->enable(rdev); +			if (ret < 0) +				return ret; + +			if (delay >= 1000) +				mdelay(delay / 1000); +			else if (delay) +				udelay(delay); +  		} else if (ret < 0) {  			printk(KERN_ERR "%s: is_enabled() failed for %s: %d\n",  			       __func__, rdev_get_name(rdev), ret); @@ -1341,6 +1388,9 @@ static int _regulator_disable(struct regulator_dev *rdev)  				       __func__, rdev_get_name(rdev));  				return ret;  			} + +			_notifier_call_chain(rdev, REGULATOR_EVENT_DISABLE, +					     NULL);  		}  		/* decrease our supplies ref count and disable if required */ @@ -1399,8 +1449,8 @@ static int _regulator_force_disable(struct regulator_dev *rdev)  			return ret;  		}  		/* notify other consumers that power has been forced off */ -		_notifier_call_chain(rdev, REGULATOR_EVENT_FORCE_DISABLE, -			NULL); +		_notifier_call_chain(rdev, REGULATOR_EVENT_FORCE_DISABLE | +			REGULATOR_EVENT_DISABLE, NULL);  	}  	/* decrease our supplies ref count and disable if required */ @@ -1434,9 +1484,9 @@ EXPORT_SYMBOL_GPL(regulator_force_disable);  static int _regulator_is_enabled(struct regulator_dev *rdev)  { -	/* sanity check */ +	/* If we don't know then assume that the regulator is always on */  	if (!rdev->desc->ops->is_enabled) -		return -EINVAL; +		return 1;  	return rdev->desc->ops->is_enabled(rdev);  } @@ -2451,8 +2501,15 @@ EXPORT_SYMBOL_GPL(regulator_get_init_drvdata);  static int __init regulator_init(void)  { +	int ret; +  	printk(KERN_INFO "regulator: core version %s\n", REGULATOR_VERSION); -	return class_register(®ulator_class); + +	ret = class_register(®ulator_class); + +	regulator_dummy_init(); + +	return ret;  }  /* init early to allow our consumers to complete system booting */ diff --git a/drivers/regulator/dummy.c b/drivers/regulator/dummy.c new file mode 100644 index 000000000000..c7410bde7b5d --- /dev/null +++ b/drivers/regulator/dummy.c @@ -0,0 +1,66 @@ +/* + * dummy.c + * + * Copyright 2010 Wolfson Microelectronics PLC. + * + * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This is useful for systems with mixed controllable and + * non-controllable regulators, as well as for allowing testing on + * systems with no controllable regulators. + */ + +#include <linux/err.h> +#include <linux/platform_device.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/machine.h> + +#include "dummy.h" + +struct regulator_dev *dummy_regulator_rdev; + +static struct regulator_init_data dummy_initdata; + +static struct regulator_ops dummy_ops; + +static struct regulator_desc dummy_desc = { +	.name = "dummy", +	.id = -1, +	.type = REGULATOR_VOLTAGE, +	.owner = THIS_MODULE, +	.ops = &dummy_ops, +}; + +static struct platform_device *dummy_pdev; + +void __init regulator_dummy_init(void) +{ +	int ret; + +	dummy_pdev = platform_device_alloc("reg-dummy", -1); +	if (!dummy_pdev) { +		pr_err("Failed to allocate dummy regulator device\n"); +		return; +	} + +	ret = platform_device_add(dummy_pdev); +	if (ret != 0) { +		pr_err("Failed to register dummy regulator device: %d\n", ret); +		platform_device_put(dummy_pdev); +		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); +		platform_device_unregister(dummy_pdev); +		return; +	} +} diff --git a/drivers/regulator/dummy.h b/drivers/regulator/dummy.h new file mode 100644 index 000000000000..3921c0e24249 --- /dev/null +++ b/drivers/regulator/dummy.h @@ -0,0 +1,31 @@ +/* + * dummy.h + * + * Copyright 2010 Wolfson Microelectronics PLC. + * + * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This is useful for systems with mixed controllable and + * non-controllable regulators, as well as for allowing testing on + * systems with no controllable regulators. + */ + +#ifndef _DUMMY_H +#define _DUMMY_H + +struct regulator_dev; + +extern struct regulator_dev *dummy_regulator_rdev; + +#ifdef CONFIG_REGULATOR_DUMMY +void __init regulator_dummy_init(void); +#else +static inline void regulator_dummy_init(void) { } +#endif + +#endif diff --git a/drivers/regulator/fixed.c b/drivers/regulator/fixed.c index f9f516a3028a..d11f7622430b 100644 --- a/drivers/regulator/fixed.c +++ b/drivers/regulator/fixed.c @@ -24,14 +24,16 @@  #include <linux/regulator/driver.h>  #include <linux/regulator/fixed.h>  #include <linux/gpio.h> +#include <linux/delay.h>  struct fixed_voltage_data {  	struct regulator_desc desc;  	struct regulator_dev *dev;  	int microvolts;  	int gpio; -	unsigned enable_high:1; -	unsigned is_enabled:1; +	unsigned startup_delay; +	bool enable_high; +	bool is_enabled;  };  static int fixed_voltage_is_enabled(struct regulator_dev *dev) @@ -47,7 +49,7 @@ static int fixed_voltage_enable(struct regulator_dev *dev)  	if (gpio_is_valid(data->gpio)) {  		gpio_set_value_cansleep(data->gpio, data->enable_high); -		data->is_enabled = 1; +		data->is_enabled = true;  	}  	return 0; @@ -59,12 +61,19 @@ static int fixed_voltage_disable(struct regulator_dev *dev)  	if (gpio_is_valid(data->gpio)) {  		gpio_set_value_cansleep(data->gpio, !data->enable_high); -		data->is_enabled = 0; +		data->is_enabled = false;  	}  	return 0;  } +static int fixed_voltage_enable_time(struct regulator_dev *dev) +{ +	struct fixed_voltage_data *data = rdev_get_drvdata(dev); + +	return data->startup_delay; +} +  static int fixed_voltage_get_voltage(struct regulator_dev *dev)  {  	struct fixed_voltage_data *data = rdev_get_drvdata(dev); @@ -87,11 +96,12 @@ static struct regulator_ops fixed_voltage_ops = {  	.is_enabled = fixed_voltage_is_enabled,  	.enable = fixed_voltage_enable,  	.disable = fixed_voltage_disable, +	.enable_time = fixed_voltage_enable_time,  	.get_voltage = fixed_voltage_get_voltage,  	.list_voltage = fixed_voltage_list_voltage,  }; -static int regulator_fixed_voltage_probe(struct platform_device *pdev) +static int __devinit reg_fixed_voltage_probe(struct platform_device *pdev)  {  	struct fixed_voltage_config *config = pdev->dev.platform_data;  	struct fixed_voltage_data *drvdata; @@ -117,6 +127,7 @@ static int regulator_fixed_voltage_probe(struct platform_device *pdev)  	drvdata->microvolts = config->microvolts;  	drvdata->gpio = config->gpio; +	drvdata->startup_delay = config->startup_delay;  	if (gpio_is_valid(config->gpio)) {  		drvdata->enable_high = config->enable_high; @@ -163,7 +174,7 @@ static int regulator_fixed_voltage_probe(struct platform_device *pdev)  		/* Regulator without GPIO control is considered  		 * always enabled  		 */ -		drvdata->is_enabled = 1; +		drvdata->is_enabled = true;  	}  	drvdata->dev = regulator_register(&drvdata->desc, &pdev->dev, @@ -191,7 +202,7 @@ err:  	return ret;  } -static int regulator_fixed_voltage_remove(struct platform_device *pdev) +static int __devexit reg_fixed_voltage_remove(struct platform_device *pdev)  {  	struct fixed_voltage_data *drvdata = platform_get_drvdata(pdev); @@ -205,10 +216,11 @@ static int regulator_fixed_voltage_remove(struct platform_device *pdev)  }  static struct platform_driver regulator_fixed_voltage_driver = { -	.probe		= regulator_fixed_voltage_probe, -	.remove		= regulator_fixed_voltage_remove, +	.probe		= reg_fixed_voltage_probe, +	.remove		= __devexit_p(reg_fixed_voltage_remove),  	.driver		= {  		.name		= "reg-fixed-voltage", +		.owner		= THIS_MODULE,  	},  }; diff --git a/drivers/regulator/lp3971.c b/drivers/regulator/lp3971.c index 4f33a0f4a179..f5532ed79272 100644 --- a/drivers/regulator/lp3971.c +++ b/drivers/regulator/lp3971.c @@ -54,7 +54,7 @@ static int lp3971_set_bits(struct lp3971 *lp3971, u8 reg, u16 mask, u16 val);  #define LP3971_BUCK2_BASE 0x29  #define LP3971_BUCK3_BASE 0x32 -const static int buck_base_addr[] = { +static const int buck_base_addr[] = {  	LP3971_BUCK1_BASE,  	LP3971_BUCK2_BASE,  	LP3971_BUCK3_BASE, @@ -63,7 +63,7 @@ const static int buck_base_addr[] = {  #define LP3971_BUCK_TARGET_VOL1_REG(x) (buck_base_addr[x])  #define LP3971_BUCK_TARGET_VOL2_REG(x) (buck_base_addr[x]+1) -const static int buck_voltage_map[] = { +static const int buck_voltage_map[] = {  	   0,  800,  850,  900,  950, 1000, 1050, 1100,  	1150, 1200, 1250, 1300, 1350, 1400, 1450, 1500,  	1550, 1600, 1650, 1700, 1800, 1900, 2500, 2800, @@ -96,17 +96,17 @@ const static int buck_voltage_map[] = {  #define LDO_VOL_CONTR_SHIFT(x) ((x & 1) << 2)  #define LDO_VOL_CONTR_MASK 0x0f -const static int ldo45_voltage_map[] = { +static const int ldo45_voltage_map[] = {  	1000, 1050, 1100, 1150, 1200, 1250, 1300, 1350,  	1400, 1500, 1800, 1900, 2500, 2800, 3000, 3300,  }; -const static int ldo123_voltage_map[] = { +static const int ldo123_voltage_map[] = {  	1800, 1900, 2000, 2100, 2200, 2300, 2400, 2500,  	2600, 2700, 2800, 2900, 3000, 3100, 3200, 3300,  }; -const static int *ldo_voltage_map[] = { +static const int *ldo_voltage_map[] = {  	ldo123_voltage_map, /* LDO1 */  	ldo123_voltage_map, /* LDO2 */  	ldo123_voltage_map, /* LDO3 */ @@ -431,20 +431,20 @@ static int lp3971_set_bits(struct lp3971 *lp3971, u8 reg, u16 mask, u16 val)  	return ret;  } -static int setup_regulators(struct lp3971 *lp3971, -	struct lp3971_platform_data *pdata) +static int __devinit setup_regulators(struct lp3971 *lp3971, +				      struct lp3971_platform_data *pdata)  {  	int i, err; -	int num_regulators = pdata->num_regulators; -	lp3971->num_regulators = num_regulators; -	lp3971->rdev = kzalloc(sizeof(struct regulator_dev *) * num_regulators, -		GFP_KERNEL); + +	lp3971->num_regulators = pdata->num_regulators; +	lp3971->rdev = kcalloc(pdata->num_regulators, +				sizeof(struct regulator_dev *), GFP_KERNEL);  	/* Instantiate the regulators */ -	for (i = 0; i < num_regulators; i++) { -		int id = pdata->regulators[i].id; -		lp3971->rdev[i] = regulator_register(®ulators[id], -			lp3971->dev, pdata->regulators[i].initdata, lp3971); +	for (i = 0; i < pdata->num_regulators; i++) { +		struct lp3971_regulator_subdev *reg = &pdata->regulators[i]; +		lp3971->rdev[i] = regulator_register(®ulators[reg->id], +					lp3971->dev, reg->initdata, lp3971);  		if (IS_ERR(lp3971->rdev[i])) {  			err = PTR_ERR(lp3971->rdev[i]); @@ -455,10 +455,10 @@ static int setup_regulators(struct lp3971 *lp3971,  	}  	return 0; +  error: -	for (i = 0; i < num_regulators; i++) -		if (lp3971->rdev[i]) -			regulator_unregister(lp3971->rdev[i]); +	while (--i >= 0) +		regulator_unregister(lp3971->rdev[i]);  	kfree(lp3971->rdev);  	lp3971->rdev = NULL;  	return err; @@ -472,15 +472,17 @@ static int __devinit lp3971_i2c_probe(struct i2c_client *i2c,  	int ret;  	u16 val; -	lp3971 = kzalloc(sizeof(struct lp3971), GFP_KERNEL); -	if (lp3971 == NULL) { -		ret = -ENOMEM; -		goto err; +	if (!pdata) { +		dev_dbg(&i2c->dev, "No platform init data supplied\n"); +		return -ENODEV;  	} +	lp3971 = kzalloc(sizeof(struct lp3971), GFP_KERNEL); +	if (lp3971 == NULL) +		return -ENOMEM; +  	lp3971->i2c = i2c;  	lp3971->dev = &i2c->dev; -	i2c_set_clientdata(i2c, lp3971);  	mutex_init(&lp3971->io_lock); @@ -493,19 +495,15 @@ static int __devinit lp3971_i2c_probe(struct i2c_client *i2c,  		goto err_detect;  	} -	if (pdata) { -		ret = setup_regulators(lp3971, pdata); -		if (ret < 0) -			goto err_detect; -	} else -		dev_warn(lp3971->dev, "No platform init data supplied\n"); +	ret = setup_regulators(lp3971, pdata); +	if (ret < 0) +		goto err_detect; +	i2c_set_clientdata(i2c, lp3971);  	return 0;  err_detect: -	i2c_set_clientdata(i2c, NULL);  	kfree(lp3971); -err:  	return ret;  } @@ -513,11 +511,13 @@ static int __devexit lp3971_i2c_remove(struct i2c_client *i2c)  {  	struct lp3971 *lp3971 = i2c_get_clientdata(i2c);  	int i; + +	i2c_set_clientdata(i2c, NULL); +  	for (i = 0; i < lp3971->num_regulators; i++) -		if (lp3971->rdev[i]) -			regulator_unregister(lp3971->rdev[i]); +		regulator_unregister(lp3971->rdev[i]); +  	kfree(lp3971->rdev); -	i2c_set_clientdata(i2c, NULL);  	kfree(lp3971);  	return 0; diff --git a/drivers/regulator/max1586.c b/drivers/regulator/max1586.c index 2c082d3ef484..a49fc952c9a9 100644 --- a/drivers/regulator/max1586.c +++ b/drivers/regulator/max1586.c @@ -179,8 +179,8 @@ static struct regulator_desc max1586_reg[] = {  	},  }; -static int max1586_pmic_probe(struct i2c_client *client, -			      const struct i2c_device_id *i2c_id) +static int __devinit max1586_pmic_probe(struct i2c_client *client, +					const struct i2c_device_id *i2c_id)  {  	struct regulator_dev **rdev;  	struct max1586_platform_data *pdata = client->dev.platform_data; @@ -235,7 +235,7 @@ out:  	return ret;  } -static int max1586_pmic_remove(struct i2c_client *client) +static int __devexit max1586_pmic_remove(struct i2c_client *client)  {  	struct regulator_dev **rdev = i2c_get_clientdata(client);  	int i; @@ -257,9 +257,10 @@ MODULE_DEVICE_TABLE(i2c, max1586_id);  static struct i2c_driver max1586_pmic_driver = {  	.probe = max1586_pmic_probe, -	.remove = max1586_pmic_remove, +	.remove = __devexit_p(max1586_pmic_remove),  	.driver		= {  		.name	= "max1586", +		.owner	= THIS_MODULE,  	},  	.id_table	= max1586_id,  }; diff --git a/drivers/regulator/max8649.c b/drivers/regulator/max8649.c new file mode 100644 index 000000000000..3ebdf698c648 --- /dev/null +++ b/drivers/regulator/max8649.c @@ -0,0 +1,408 @@ +/* + * Regulators driver for Maxim max8649 + * + * Copyright (C) 2009-2010 Marvell International Ltd. + *      Haojian Zhuang <haojian.zhuang@marvell.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/err.h> +#include <linux/i2c.h> +#include <linux/platform_device.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/max8649.h> + +#define MAX8649_DCDC_VMIN	750000		/* uV */ +#define MAX8649_DCDC_VMAX	1380000		/* uV */ +#define MAX8649_DCDC_STEP	10000		/* uV */ +#define MAX8649_VOL_MASK	0x3f + +/* Registers */ +#define MAX8649_MODE0		0x00 +#define MAX8649_MODE1		0x01 +#define MAX8649_MODE2		0x02 +#define MAX8649_MODE3		0x03 +#define MAX8649_CONTROL		0x04 +#define MAX8649_SYNC		0x05 +#define MAX8649_RAMP		0x06 +#define MAX8649_CHIP_ID1	0x08 +#define MAX8649_CHIP_ID2	0x09 + +/* Bits */ +#define MAX8649_EN_PD		(1 << 7) +#define MAX8649_VID0_PD		(1 << 6) +#define MAX8649_VID1_PD		(1 << 5) +#define MAX8649_VID_MASK	(3 << 5) + +#define MAX8649_FORCE_PWM	(1 << 7) +#define MAX8649_SYNC_EXTCLK	(1 << 6) + +#define MAX8649_EXT_MASK	(3 << 6) + +#define MAX8649_RAMP_MASK	(7 << 5) +#define MAX8649_RAMP_DOWN	(1 << 1) + +struct max8649_regulator_info { +	struct regulator_dev	*regulator; +	struct i2c_client	*i2c; +	struct device		*dev; +	struct mutex		io_lock; + +	int		vol_reg; +	unsigned	mode:2;	/* bit[1:0] = VID1, VID0 */ +	unsigned	extclk_freq:2; +	unsigned	extclk:1; +	unsigned	ramp_timing:3; +	unsigned	ramp_down:1; +}; + +/* I2C operations */ + +static inline int max8649_read_device(struct i2c_client *i2c, +				      int reg, int bytes, void *dest) +{ +	unsigned char data; +	int ret; + +	data = (unsigned char)reg; +	ret = i2c_master_send(i2c, &data, 1); +	if (ret < 0) +		return ret; +	ret = i2c_master_recv(i2c, dest, bytes); +	if (ret < 0) +		return ret; +	return 0; +} + +static inline int max8649_write_device(struct i2c_client *i2c, +				       int reg, int bytes, void *src) +{ +	unsigned char buf[bytes + 1]; +	int ret; + +	buf[0] = (unsigned char)reg; +	memcpy(&buf[1], src, bytes); + +	ret = i2c_master_send(i2c, buf, bytes + 1); +	if (ret < 0) +		return ret; +	return 0; +} + +static int max8649_reg_read(struct i2c_client *i2c, int reg) +{ +	struct max8649_regulator_info *info = i2c_get_clientdata(i2c); +	unsigned char data; +	int ret; + +	mutex_lock(&info->io_lock); +	ret = max8649_read_device(i2c, reg, 1, &data); +	mutex_unlock(&info->io_lock); + +	if (ret < 0) +		return ret; +	return (int)data; +} + +static int max8649_set_bits(struct i2c_client *i2c, int reg, +			    unsigned char mask, unsigned char data) +{ +	struct max8649_regulator_info *info = i2c_get_clientdata(i2c); +	unsigned char value; +	int ret; + +	mutex_lock(&info->io_lock); +	ret = max8649_read_device(i2c, reg, 1, &value); +	if (ret < 0) +		goto out; +	value &= ~mask; +	value |= data; +	ret = max8649_write_device(i2c, reg, 1, &value); +out: +	mutex_unlock(&info->io_lock); +	return ret; +} + +static inline int check_range(int min_uV, int max_uV) +{ +	if ((min_uV < MAX8649_DCDC_VMIN) || (max_uV > MAX8649_DCDC_VMAX) +		|| (min_uV > max_uV)) +		return -EINVAL; +	return 0; +} + +static int max8649_list_voltage(struct regulator_dev *rdev, unsigned index) +{ +	return (MAX8649_DCDC_VMIN + index * MAX8649_DCDC_STEP); +} + +static int max8649_get_voltage(struct regulator_dev *rdev) +{ +	struct max8649_regulator_info *info = rdev_get_drvdata(rdev); +	unsigned char data; +	int ret; + +	ret = max8649_reg_read(info->i2c, info->vol_reg); +	if (ret < 0) +		return ret; +	data = (unsigned char)ret & MAX8649_VOL_MASK; +	return max8649_list_voltage(rdev, data); +} + +static int max8649_set_voltage(struct regulator_dev *rdev, +			       int min_uV, int max_uV) +{ +	struct max8649_regulator_info *info = rdev_get_drvdata(rdev); +	unsigned char data, mask; + +	if (check_range(min_uV, max_uV)) { +		dev_err(info->dev, "invalid voltage range (%d, %d) uV\n", +			min_uV, max_uV); +		return -EINVAL; +	} +	data = (min_uV - MAX8649_DCDC_VMIN + MAX8649_DCDC_STEP - 1) +		/ MAX8649_DCDC_STEP; +	mask = MAX8649_VOL_MASK; + +	return max8649_set_bits(info->i2c, info->vol_reg, mask, data); +} + +/* EN_PD means pulldown on EN input */ +static int max8649_enable(struct regulator_dev *rdev) +{ +	struct max8649_regulator_info *info = rdev_get_drvdata(rdev); +	return max8649_set_bits(info->i2c, MAX8649_CONTROL, MAX8649_EN_PD, 0); +} + +/* + * Applied internal pulldown resistor on EN input pin. + * If pulldown EN pin outside, it would be better. + */ +static int max8649_disable(struct regulator_dev *rdev) +{ +	struct max8649_regulator_info *info = rdev_get_drvdata(rdev); +	return max8649_set_bits(info->i2c, MAX8649_CONTROL, MAX8649_EN_PD, +				MAX8649_EN_PD); +} + +static int max8649_is_enabled(struct regulator_dev *rdev) +{ +	struct max8649_regulator_info *info = rdev_get_drvdata(rdev); +	int ret; + +	ret = max8649_reg_read(info->i2c, MAX8649_CONTROL); +	if (ret < 0) +		return ret; +	return !((unsigned char)ret & MAX8649_EN_PD); +} + +static int max8649_enable_time(struct regulator_dev *rdev) +{ +	struct max8649_regulator_info *info = rdev_get_drvdata(rdev); +	int voltage, rate, ret; + +	/* get voltage */ +	ret = max8649_reg_read(info->i2c, info->vol_reg); +	if (ret < 0) +		return ret; +	ret &= MAX8649_VOL_MASK; +	voltage = max8649_list_voltage(rdev, (unsigned char)ret); /* uV */ + +	/* get rate */ +	ret = max8649_reg_read(info->i2c, MAX8649_RAMP); +	if (ret < 0) +		return ret; +	ret = (ret & MAX8649_RAMP_MASK) >> 5; +	rate = (32 * 1000) >> ret;	/* uV/uS */ + +	return (voltage / rate); +} + +static int max8649_set_mode(struct regulator_dev *rdev, unsigned int mode) +{ +	struct max8649_regulator_info *info = rdev_get_drvdata(rdev); + +	switch (mode) { +	case REGULATOR_MODE_FAST: +		max8649_set_bits(info->i2c, info->vol_reg, MAX8649_FORCE_PWM, +				 MAX8649_FORCE_PWM); +		break; +	case REGULATOR_MODE_NORMAL: +		max8649_set_bits(info->i2c, info->vol_reg, +				 MAX8649_FORCE_PWM, 0); +		break; +	default: +		return -EINVAL; +	} +	return 0; +} + +static unsigned int max8649_get_mode(struct regulator_dev *rdev) +{ +	struct max8649_regulator_info *info = rdev_get_drvdata(rdev); +	int ret; + +	ret = max8649_reg_read(info->i2c, info->vol_reg); +	if (ret & MAX8649_FORCE_PWM) +		return REGULATOR_MODE_FAST; +	return REGULATOR_MODE_NORMAL; +} + +static struct regulator_ops max8649_dcdc_ops = { +	.set_voltage	= max8649_set_voltage, +	.get_voltage	= max8649_get_voltage, +	.list_voltage	= max8649_list_voltage, +	.enable		= max8649_enable, +	.disable	= max8649_disable, +	.is_enabled	= max8649_is_enabled, +	.enable_time	= max8649_enable_time, +	.set_mode	= max8649_set_mode, +	.get_mode	= max8649_get_mode, + +}; + +static struct regulator_desc dcdc_desc = { +	.name		= "max8649", +	.ops		= &max8649_dcdc_ops, +	.type		= REGULATOR_VOLTAGE, +	.n_voltages	= 1 << 6, +	.owner		= THIS_MODULE, +}; + +static int __devinit max8649_regulator_probe(struct i2c_client *client, +					     const struct i2c_device_id *id) +{ +	struct max8649_platform_data *pdata = client->dev.platform_data; +	struct max8649_regulator_info *info = NULL; +	unsigned char data; +	int ret; + +	info = kzalloc(sizeof(struct max8649_regulator_info), GFP_KERNEL); +	if (!info) { +		dev_err(&client->dev, "No enough memory\n"); +		return -ENOMEM; +	} + +	info->i2c = client; +	info->dev = &client->dev; +	mutex_init(&info->io_lock); +	i2c_set_clientdata(client, info); + +	info->mode = pdata->mode; +	switch (info->mode) { +	case 0: +		info->vol_reg = MAX8649_MODE0; +		break; +	case 1: +		info->vol_reg = MAX8649_MODE1; +		break; +	case 2: +		info->vol_reg = MAX8649_MODE2; +		break; +	case 3: +		info->vol_reg = MAX8649_MODE3; +		break; +	default: +		break; +	} + +	ret = max8649_reg_read(info->i2c, MAX8649_CHIP_ID1); +	if (ret < 0) { +		dev_err(info->dev, "Failed to detect ID of MAX8649:%d\n", +			ret); +		goto out; +	} +	dev_info(info->dev, "Detected MAX8649 (ID:%x)\n", ret); + +	/* enable VID0 & VID1 */ +	max8649_set_bits(info->i2c, MAX8649_CONTROL, MAX8649_VID_MASK, 0); + +	/* enable/disable external clock synchronization */ +	info->extclk = pdata->extclk; +	data = (info->extclk) ? MAX8649_SYNC_EXTCLK : 0; +	max8649_set_bits(info->i2c, info->vol_reg, MAX8649_SYNC_EXTCLK, data); +	if (info->extclk) { +		/* set external clock frequency */ +		info->extclk_freq = pdata->extclk_freq; +		max8649_set_bits(info->i2c, MAX8649_SYNC, MAX8649_EXT_MASK, +				 info->extclk_freq); +	} + +	if (pdata->ramp_timing) { +		info->ramp_timing = pdata->ramp_timing; +		max8649_set_bits(info->i2c, MAX8649_RAMP, MAX8649_RAMP_MASK, +				 info->ramp_timing << 5); +	} + +	info->ramp_down = pdata->ramp_down; +	if (info->ramp_down) { +		max8649_set_bits(info->i2c, MAX8649_RAMP, MAX8649_RAMP_DOWN, +				 MAX8649_RAMP_DOWN); +	} + +	info->regulator = regulator_register(&dcdc_desc, &client->dev, +					     pdata->regulator, info); +	if (IS_ERR(info->regulator)) { +		dev_err(info->dev, "failed to register regulator %s\n", +			dcdc_desc.name); +		ret = PTR_ERR(info->regulator); +		goto out; +	} + +	dev_info(info->dev, "Max8649 regulator device is detected.\n"); +	return 0; +out: +	kfree(info); +	return ret; +} + +static int __devexit max8649_regulator_remove(struct i2c_client *client) +{ +	struct max8649_regulator_info *info = i2c_get_clientdata(client); + +	if (info) { +		if (info->regulator) +			regulator_unregister(info->regulator); +		kfree(info); +	} +	i2c_set_clientdata(client, NULL); + +	return 0; +} + +static const struct i2c_device_id max8649_id[] = { +	{ "max8649", 0 }, +	{ } +}; +MODULE_DEVICE_TABLE(i2c, max8649_id); + +static struct i2c_driver max8649_driver = { +	.probe		= max8649_regulator_probe, +	.remove		= __devexit_p(max8649_regulator_remove), +	.driver		= { +		.name	= "max8649", +	}, +	.id_table	= max8649_id, +}; + +static int __init max8649_init(void) +{ +	return i2c_add_driver(&max8649_driver); +} +subsys_initcall(max8649_init); + +static void __exit max8649_exit(void) +{ +	i2c_del_driver(&max8649_driver); +} +module_exit(max8649_exit); + +/* Module information */ +MODULE_DESCRIPTION("MAXIM 8649 voltage regulator driver"); +MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>"); +MODULE_LICENSE("GPL"); + diff --git a/drivers/regulator/max8660.c b/drivers/regulator/max8660.c index acc2fb7b6087..f12f1bb62138 100644 --- a/drivers/regulator/max8660.c +++ b/drivers/regulator/max8660.c @@ -345,8 +345,8 @@ static struct regulator_desc max8660_reg[] = {  	},  }; -static int max8660_probe(struct i2c_client *client, -			      const struct i2c_device_id *i2c_id) +static int __devinit max8660_probe(struct i2c_client *client, +				   const struct i2c_device_id *i2c_id)  {  	struct regulator_dev **rdev;  	struct max8660_platform_data *pdata = client->dev.platform_data; @@ -354,7 +354,7 @@ static int max8660_probe(struct i2c_client *client,  	int boot_on, i, id, ret = -EINVAL;  	if (pdata->num_subdevs > MAX8660_V_END) { -		dev_err(&client->dev, "Too much regulators found!\n"); +		dev_err(&client->dev, "Too many regulators found!\n");  		goto out;  	} @@ -462,7 +462,7 @@ out:  	return ret;  } -static int max8660_remove(struct i2c_client *client) +static int __devexit max8660_remove(struct i2c_client *client)  {  	struct regulator_dev **rdev = i2c_get_clientdata(client);  	int i; @@ -485,9 +485,10 @@ MODULE_DEVICE_TABLE(i2c, max8660_id);  static struct i2c_driver max8660_driver = {  	.probe = max8660_probe, -	.remove = max8660_remove, +	.remove = __devexit_p(max8660_remove),  	.driver		= {  		.name	= "max8660", +		.owner	= THIS_MODULE,  	},  	.id_table	= max8660_id,  }; diff --git a/drivers/regulator/mc13783-regulator.c b/drivers/regulator/mc13783-regulator.c index 39c495300045..f7b81845a196 100644 --- a/drivers/regulator/mc13783-regulator.c +++ b/drivers/regulator/mc13783-regulator.c @@ -2,6 +2,7 @@   * Regulator Driver for Freescale MC13783 PMIC   *   * Copyright (C) 2008 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de> + * Copyright 2009 Alberto Panizzo <maramaopercheseimorto@gmail.com>   *   * This program is free software; you can redistribute it and/or modify   * it under the terms of the GNU General Public License version 2 as @@ -16,11 +17,44 @@  #include <linux/init.h>  #include <linux/err.h> -#define MC13783_REG_SWITCHERS4			28 -#define MC13783_REG_SWITCHERS4_PLLEN			(1 << 18) -  #define MC13783_REG_SWITCHERS5			29  #define MC13783_REG_SWITCHERS5_SW3EN			(1 << 20) +#define MC13783_REG_SWITCHERS5_SW3VSEL			18 +#define MC13783_REG_SWITCHERS5_SW3VSEL_M		(3 << 18) + +#define MC13783_REG_REGULATORSETTING0		30 +#define MC13783_REG_REGULATORSETTING0_VIOLOVSEL		2 +#define MC13783_REG_REGULATORSETTING0_VDIGVSEL		4 +#define MC13783_REG_REGULATORSETTING0_VGENVSEL		6 +#define MC13783_REG_REGULATORSETTING0_VRFDIGVSEL	9 +#define MC13783_REG_REGULATORSETTING0_VRFREFVSEL	11 +#define MC13783_REG_REGULATORSETTING0_VRFCPVSEL		13 +#define MC13783_REG_REGULATORSETTING0_VSIMVSEL		14 +#define MC13783_REG_REGULATORSETTING0_VESIMVSEL		15 +#define MC13783_REG_REGULATORSETTING0_VCAMVSEL		16 + +#define MC13783_REG_REGULATORSETTING0_VIOLOVSEL_M	(3 << 2) +#define MC13783_REG_REGULATORSETTING0_VDIGVSEL_M	(3 << 4) +#define MC13783_REG_REGULATORSETTING0_VGENVSEL_M	(7 << 6) +#define MC13783_REG_REGULATORSETTING0_VRFDIGVSEL_M	(3 << 9) +#define MC13783_REG_REGULATORSETTING0_VRFREFVSEL_M	(3 << 11) +#define MC13783_REG_REGULATORSETTING0_VRFCPVSEL_M	(1 << 13) +#define MC13783_REG_REGULATORSETTING0_VSIMVSEL_M	(1 << 14) +#define MC13783_REG_REGULATORSETTING0_VESIMVSEL_M	(1 << 15) +#define MC13783_REG_REGULATORSETTING0_VCAMVSEL_M	(7 << 16) + +#define MC13783_REG_REGULATORSETTING1		31 +#define MC13783_REG_REGULATORSETTING1_VVIBVSEL		0 +#define MC13783_REG_REGULATORSETTING1_VRF1VSEL		2 +#define MC13783_REG_REGULATORSETTING1_VRF2VSEL		4 +#define MC13783_REG_REGULATORSETTING1_VMMC1VSEL		6 +#define MC13783_REG_REGULATORSETTING1_VMMC2VSEL		9 + +#define MC13783_REG_REGULATORSETTING1_VVIBVSEL_M	(3 << 0) +#define MC13783_REG_REGULATORSETTING1_VRF1VSEL_M	(3 << 2) +#define MC13783_REG_REGULATORSETTING1_VRF2VSEL_M	(3 << 4) +#define MC13783_REG_REGULATORSETTING1_VMMC1VSEL_M	(7 << 6) +#define MC13783_REG_REGULATORSETTING1_VMMC2VSEL_M	(7 << 9)  #define MC13783_REG_REGULATORMODE0		32  #define MC13783_REG_REGULATORMODE0_VAUDIOEN		(1 << 0) @@ -48,19 +82,107 @@  #define MC13783_REG_POWERMISC_GPO2EN			(1 << 8)  #define MC13783_REG_POWERMISC_GPO3EN			(1 << 10)  #define MC13783_REG_POWERMISC_GPO4EN			(1 << 12) +#define MC13783_REG_POWERMISC_PWGT1SPIEN		(1 << 15) +#define MC13783_REG_POWERMISC_PWGT2SPIEN		(1 << 16) + +#define MC13783_REG_POWERMISC_PWGTSPI_M			(3 << 15) +  struct mc13783_regulator {  	struct regulator_desc desc;  	int reg;  	int enable_bit; +	int vsel_reg; +	int vsel_shift; +	int vsel_mask; +	int const *voltages; +}; + +/* Voltage Values */ +static const int const mc13783_sw3_val[] = { +	5000000, 5000000, 5000000, 5500000, +}; + +static const int const mc13783_vaudio_val[] = { +	2775000, +}; + +static const int const mc13783_viohi_val[] = { +	2775000, +}; + +static const int const mc13783_violo_val[] = { +	1200000, 1300000, 1500000, 1800000, +}; + +static const int const mc13783_vdig_val[] = { +	1200000, 1300000, 1500000, 1800000, +}; + +static const int const mc13783_vgen_val[] = { +	1200000, 1300000, 1500000, 1800000, +	1100000, 2000000, 2775000, 2400000, +}; + +static const int const mc13783_vrfdig_val[] = { +	1200000, 1500000, 1800000, 1875000, +}; + +static const int const mc13783_vrfref_val[] = { +	2475000, 2600000, 2700000, 2775000, +}; + +static const int const mc13783_vrfcp_val[] = { +	2700000, 2775000, +}; + +static const int const mc13783_vsim_val[] = { +	1800000, 2900000, 3000000, +}; + +static const int const mc13783_vesim_val[] = { +	1800000, 2900000, +}; + +static const int const mc13783_vcam_val[] = { +	1500000, 1800000, 2500000, 2550000, +	2600000, 2750000, 2800000, 3000000, +}; + +static const int const mc13783_vrfbg_val[] = { +	1250000, +}; + +static const int const mc13783_vvib_val[] = { +	1300000, 1800000, 2000000, 3000000, +}; + +static const int const mc13783_vmmc_val[] = { +	1600000, 1800000, 2000000, 2600000, +	2700000, 2800000, 2900000, 3000000, +}; + +static const int const mc13783_vrf_val[] = { +	1500000, 1875000, 2700000, 2775000, +}; + +static const int const mc13783_gpo_val[] = { +	3100000, +}; + +static const int const mc13783_pwgtdrv_val[] = { +	5500000,  };  static struct regulator_ops mc13783_regulator_ops; +static struct regulator_ops mc13783_fixed_regulator_ops; +static struct regulator_ops mc13783_gpo_regulator_ops; -#define MC13783_DEFINE(prefix, _name, _reg)				\ +#define MC13783_DEFINE(prefix, _name, _reg, _vsel_reg, _voltages)	\  	[MC13783_ ## prefix ## _ ## _name] = {				\  		.desc = {						\  			.name = #prefix "_" #_name,			\ +			.n_voltages = ARRAY_SIZE(_voltages),		\  			.ops = &mc13783_regulator_ops,			\  			.type = REGULATOR_VOLTAGE,			\  			.id = MC13783_ ## prefix ## _ ## _name,		\ @@ -68,40 +190,92 @@ static struct regulator_ops mc13783_regulator_ops;  		},							\  		.reg = MC13783_REG_ ## _reg,				\  		.enable_bit = MC13783_REG_ ## _reg ## _ ## _name ## EN,	\ +		.vsel_reg = MC13783_REG_ ## _vsel_reg,			\ +		.vsel_shift = MC13783_REG_ ## _vsel_reg ## _ ## _name ## VSEL,\ +		.vsel_mask = MC13783_REG_ ## _vsel_reg ## _ ## _name ## VSEL_M,\ +		.voltages =  _voltages,					\ +	} + +#define MC13783_FIXED_DEFINE(prefix, _name, _reg, _voltages)		\ +	[MC13783_ ## prefix ## _ ## _name] = {				\ +		.desc = {						\ +			.name = #prefix "_" #_name,			\ +			.n_voltages = ARRAY_SIZE(_voltages),		\ +			.ops = &mc13783_fixed_regulator_ops,		\ +			.type = REGULATOR_VOLTAGE,			\ +			.id = MC13783_ ## prefix ## _ ## _name,		\ +			.owner = THIS_MODULE,				\ +		},							\ +		.reg = MC13783_REG_ ## _reg,				\ +		.enable_bit = MC13783_REG_ ## _reg ## _ ## _name ## EN,	\ +		.voltages =  _voltages,					\  	} -#define MC13783_DEFINE_SW(_name, _reg) MC13783_DEFINE(SW, _name, _reg) -#define MC13783_DEFINE_REGU(_name, _reg) MC13783_DEFINE(REGU, _name, _reg) +#define MC13783_GPO_DEFINE(prefix, _name, _reg,  _voltages)		\ +	[MC13783_ ## prefix ## _ ## _name] = {				\ +		.desc = {						\ +			.name = #prefix "_" #_name,			\ +			.n_voltages = ARRAY_SIZE(_voltages),		\ +			.ops = &mc13783_gpo_regulator_ops,		\ +			.type = REGULATOR_VOLTAGE,			\ +			.id = MC13783_ ## prefix ## _ ## _name,		\ +			.owner = THIS_MODULE,				\ +		},							\ +		.reg = MC13783_REG_ ## _reg,				\ +		.enable_bit = MC13783_REG_ ## _reg ## _ ## _name ## EN,	\ +		.voltages =  _voltages,					\ +	} + +#define MC13783_DEFINE_SW(_name, _reg, _vsel_reg, _voltages)		\ +	MC13783_DEFINE(SW, _name, _reg, _vsel_reg, _voltages) +#define MC13783_DEFINE_REGU(_name, _reg, _vsel_reg, _voltages)		\ +	MC13783_DEFINE(REGU, _name, _reg, _vsel_reg, _voltages)  static struct mc13783_regulator mc13783_regulators[] = { -	MC13783_DEFINE_SW(SW3, SWITCHERS5), -	MC13783_DEFINE_SW(PLL, SWITCHERS4), - -	MC13783_DEFINE_REGU(VAUDIO, REGULATORMODE0), -	MC13783_DEFINE_REGU(VIOHI, REGULATORMODE0), -	MC13783_DEFINE_REGU(VIOLO, REGULATORMODE0), -	MC13783_DEFINE_REGU(VDIG, REGULATORMODE0), -	MC13783_DEFINE_REGU(VGEN, REGULATORMODE0), -	MC13783_DEFINE_REGU(VRFDIG, REGULATORMODE0), -	MC13783_DEFINE_REGU(VRFREF, REGULATORMODE0), -	MC13783_DEFINE_REGU(VRFCP, REGULATORMODE0), -	MC13783_DEFINE_REGU(VSIM, REGULATORMODE1), -	MC13783_DEFINE_REGU(VESIM, REGULATORMODE1), -	MC13783_DEFINE_REGU(VCAM, REGULATORMODE1), -	MC13783_DEFINE_REGU(VRFBG, REGULATORMODE1), -	MC13783_DEFINE_REGU(VVIB, REGULATORMODE1), -	MC13783_DEFINE_REGU(VRF1, REGULATORMODE1), -	MC13783_DEFINE_REGU(VRF2, REGULATORMODE1), -	MC13783_DEFINE_REGU(VMMC1, REGULATORMODE1), -	MC13783_DEFINE_REGU(VMMC2, REGULATORMODE1), -	MC13783_DEFINE_REGU(GPO1, POWERMISC), -	MC13783_DEFINE_REGU(GPO2, POWERMISC), -	MC13783_DEFINE_REGU(GPO3, POWERMISC), -	MC13783_DEFINE_REGU(GPO4, POWERMISC), +	MC13783_DEFINE_SW(SW3, SWITCHERS5, SWITCHERS5, mc13783_sw3_val), + +	MC13783_FIXED_DEFINE(REGU, VAUDIO, REGULATORMODE0, mc13783_vaudio_val), +	MC13783_FIXED_DEFINE(REGU, VIOHI, REGULATORMODE0, mc13783_viohi_val), +	MC13783_DEFINE_REGU(VIOLO, REGULATORMODE0, REGULATORSETTING0,	\ +			    mc13783_violo_val), +	MC13783_DEFINE_REGU(VDIG, REGULATORMODE0, REGULATORSETTING0,	\ +			    mc13783_vdig_val), +	MC13783_DEFINE_REGU(VGEN, REGULATORMODE0, REGULATORSETTING0,	\ +			    mc13783_vgen_val), +	MC13783_DEFINE_REGU(VRFDIG, REGULATORMODE0, REGULATORSETTING0,	\ +			    mc13783_vrfdig_val), +	MC13783_DEFINE_REGU(VRFREF, REGULATORMODE0, REGULATORSETTING0,	\ +			    mc13783_vrfref_val), +	MC13783_DEFINE_REGU(VRFCP, REGULATORMODE0, REGULATORSETTING0,	\ +			    mc13783_vrfcp_val), +	MC13783_DEFINE_REGU(VSIM, REGULATORMODE1, REGULATORSETTING0,	\ +			    mc13783_vsim_val), +	MC13783_DEFINE_REGU(VESIM, REGULATORMODE1, REGULATORSETTING0,	\ +			    mc13783_vesim_val), +	MC13783_DEFINE_REGU(VCAM, REGULATORMODE1, REGULATORSETTING0,	\ +			    mc13783_vcam_val), +	MC13783_FIXED_DEFINE(REGU, VRFBG, REGULATORMODE1, mc13783_vrfbg_val), +	MC13783_DEFINE_REGU(VVIB, REGULATORMODE1, REGULATORSETTING1,	\ +			    mc13783_vvib_val), +	MC13783_DEFINE_REGU(VRF1, REGULATORMODE1, REGULATORSETTING1,	\ +			    mc13783_vrf_val), +	MC13783_DEFINE_REGU(VRF2, REGULATORMODE1, REGULATORSETTING1,	\ +			    mc13783_vrf_val), +	MC13783_DEFINE_REGU(VMMC1, REGULATORMODE1, REGULATORSETTING1,	\ +			    mc13783_vmmc_val), +	MC13783_DEFINE_REGU(VMMC2, REGULATORMODE1, REGULATORSETTING1,	\ +			    mc13783_vmmc_val), +	MC13783_GPO_DEFINE(REGU, GPO1, POWERMISC, mc13783_gpo_val), +	MC13783_GPO_DEFINE(REGU, GPO2, POWERMISC, mc13783_gpo_val), +	MC13783_GPO_DEFINE(REGU, GPO3, POWERMISC, mc13783_gpo_val), +	MC13783_GPO_DEFINE(REGU, GPO4, POWERMISC, mc13783_gpo_val), +	MC13783_GPO_DEFINE(REGU, PWGT1SPI, POWERMISC, mc13783_pwgtdrv_val), +	MC13783_GPO_DEFINE(REGU, PWGT2SPI, POWERMISC, mc13783_pwgtdrv_val),  };  struct mc13783_regulator_priv {  	struct mc13783 *mc13783; +	u32 powermisc_pwgt_state;  	struct regulator_dev *regulators[];  }; @@ -154,10 +328,241 @@ static int mc13783_regulator_is_enabled(struct regulator_dev *rdev)  	return (val & mc13783_regulators[id].enable_bit) != 0;  } +static int mc13783_regulator_list_voltage(struct regulator_dev *rdev, +						unsigned selector) +{ +	int id = rdev_get_id(rdev); + +	if (selector >= mc13783_regulators[id].desc.n_voltages) +		return -EINVAL; + +	return mc13783_regulators[id].voltages[selector]; +} + +static int mc13783_get_best_voltage_index(struct regulator_dev *rdev, +						int min_uV, int max_uV) +{ +	int reg_id = rdev_get_id(rdev); +	int i; +	int bestmatch; +	int bestindex; + +	/* +	 * Locate the minimum voltage fitting the criteria on +	 * this regulator. The switchable voltages are not +	 * in strict falling order so we need to check them +	 * all for the best match. +	 */ +	bestmatch = INT_MAX; +	bestindex = -1; +	for (i = 0; i < mc13783_regulators[reg_id].desc.n_voltages; i++) { +		if (mc13783_regulators[reg_id].voltages[i] >= min_uV && +		    mc13783_regulators[reg_id].voltages[i] < bestmatch) { +			bestmatch = mc13783_regulators[reg_id].voltages[i]; +			bestindex = i; +		} +	} + +	if (bestindex < 0 || bestmatch > max_uV) { +		dev_warn(&rdev->dev, "no possible value for %d<=x<=%d uV\n", +				min_uV, max_uV); +		return -EINVAL; +	} +	return bestindex; +} + +static int mc13783_regulator_set_voltage(struct regulator_dev *rdev, +						int min_uV, int max_uV) +{ +	struct mc13783_regulator_priv *priv = rdev_get_drvdata(rdev); +	int value, id = rdev_get_id(rdev); +	int ret; + +	dev_dbg(rdev_get_dev(rdev), "%s id: %d min_uV: %d max_uV: %d\n", +		__func__, id, min_uV, max_uV); + +	/* Find the best index */ +	value = mc13783_get_best_voltage_index(rdev, min_uV, max_uV); +	dev_dbg(rdev_get_dev(rdev), "%s best value: %d \n", __func__, value); +	if (value < 0) +		return value; + +	mc13783_lock(priv->mc13783); +	ret = mc13783_reg_rmw(priv->mc13783, mc13783_regulators[id].vsel_reg, +			mc13783_regulators[id].vsel_mask, +			value << mc13783_regulators[id].vsel_shift); +	mc13783_unlock(priv->mc13783); + +	return ret; +} + +static int mc13783_regulator_get_voltage(struct regulator_dev *rdev) +{ +	struct mc13783_regulator_priv *priv = rdev_get_drvdata(rdev); +	int ret, id = rdev_get_id(rdev); +	unsigned int val; + +	dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id); + +	mc13783_lock(priv->mc13783); +	ret = mc13783_reg_read(priv->mc13783, +				mc13783_regulators[id].vsel_reg, &val); +	mc13783_unlock(priv->mc13783); + +	if (ret) +		return ret; + +	val = (val & mc13783_regulators[id].vsel_mask) +		>> mc13783_regulators[id].vsel_shift; + +	dev_dbg(rdev_get_dev(rdev), "%s id: %d val: %d\n", __func__, id, val); + +	BUG_ON(val < 0 || val > mc13783_regulators[id].desc.n_voltages); + +	return mc13783_regulators[id].voltages[val]; +} +  static struct regulator_ops mc13783_regulator_ops = {  	.enable = mc13783_regulator_enable,  	.disable = mc13783_regulator_disable,  	.is_enabled = mc13783_regulator_is_enabled, +	.list_voltage = mc13783_regulator_list_voltage, +	.set_voltage = mc13783_regulator_set_voltage, +	.get_voltage = mc13783_regulator_get_voltage, +}; + +static int mc13783_fixed_regulator_set_voltage(struct regulator_dev *rdev, +						int min_uV, int max_uV) +{ +	int id = rdev_get_id(rdev); + +	dev_dbg(rdev_get_dev(rdev), "%s id: %d min_uV: %d max_uV: %d\n", +		__func__, id, min_uV, max_uV); + +	if (min_uV > mc13783_regulators[id].voltages[0] && +	    max_uV < mc13783_regulators[id].voltages[0]) +		return 0; +	else +		return -EINVAL; +} + +static int mc13783_fixed_regulator_get_voltage(struct regulator_dev *rdev) +{ +	int id = rdev_get_id(rdev); + +	dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id); + +	return mc13783_regulators[id].voltages[0]; +} + +static struct regulator_ops mc13783_fixed_regulator_ops = { +	.enable = mc13783_regulator_enable, +	.disable = mc13783_regulator_disable, +	.is_enabled = mc13783_regulator_is_enabled, +	.list_voltage = mc13783_regulator_list_voltage, +	.set_voltage = mc13783_fixed_regulator_set_voltage, +	.get_voltage = mc13783_fixed_regulator_get_voltage, +}; + +int mc13783_powermisc_rmw(struct mc13783_regulator_priv *priv, u32 mask, +									u32 val) +{ +	struct mc13783 *mc13783 = priv->mc13783; +	int ret; +	u32 valread; + +	BUG_ON(val & ~mask); + +	ret = mc13783_reg_read(mc13783, MC13783_REG_POWERMISC, &valread); +	if (ret) +		return ret; + +	/* Update the stored state for Power Gates. */ +	priv->powermisc_pwgt_state = +				(priv->powermisc_pwgt_state & ~mask) | val; +	priv->powermisc_pwgt_state &= MC13783_REG_POWERMISC_PWGTSPI_M; + +	/* Construct the new register value */ +	valread = (valread & ~mask) | val; +	/* Overwrite the PWGTxEN with the stored version */ +	valread = (valread & ~MC13783_REG_POWERMISC_PWGTSPI_M) | +						priv->powermisc_pwgt_state; + +	return mc13783_reg_write(mc13783, MC13783_REG_POWERMISC, valread); +} + +static int mc13783_gpo_regulator_enable(struct regulator_dev *rdev) +{ +	struct mc13783_regulator_priv *priv = rdev_get_drvdata(rdev); +	int id = rdev_get_id(rdev); +	int ret; +	u32 en_val = mc13783_regulators[id].enable_bit; + +	dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id); + +	/* Power Gate enable value is 0 */ +	if (id == MC13783_REGU_PWGT1SPI || +	    id == MC13783_REGU_PWGT2SPI) +		en_val = 0; + +	mc13783_lock(priv->mc13783); +	ret = mc13783_powermisc_rmw(priv, mc13783_regulators[id].enable_bit, +					en_val); +	mc13783_unlock(priv->mc13783); + +	return ret; +} + +static int mc13783_gpo_regulator_disable(struct regulator_dev *rdev) +{ +	struct mc13783_regulator_priv *priv = rdev_get_drvdata(rdev); +	int id = rdev_get_id(rdev); +	int ret; +	u32 dis_val = 0; + +	dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id); + +	/* Power Gate disable value is 1 */ +	if (id == MC13783_REGU_PWGT1SPI || +	    id == MC13783_REGU_PWGT2SPI) +		dis_val = mc13783_regulators[id].enable_bit; + +	mc13783_lock(priv->mc13783); +	ret = mc13783_powermisc_rmw(priv, mc13783_regulators[id].enable_bit, +					dis_val); +	mc13783_unlock(priv->mc13783); + +	return ret; +} + +static int mc13783_gpo_regulator_is_enabled(struct regulator_dev *rdev) +{ +	struct mc13783_regulator_priv *priv = rdev_get_drvdata(rdev); +	int ret, id = rdev_get_id(rdev); +	unsigned int val; + +	mc13783_lock(priv->mc13783); +	ret = mc13783_reg_read(priv->mc13783, mc13783_regulators[id].reg, &val); +	mc13783_unlock(priv->mc13783); + +	if (ret) +		return ret; + +	/* Power Gates state is stored in powermisc_pwgt_state +	 * where the meaning of bits is negated */ +	val = (val & ~MC13783_REG_POWERMISC_PWGTSPI_M) | +	      (priv->powermisc_pwgt_state ^ MC13783_REG_POWERMISC_PWGTSPI_M); + +	return (val & mc13783_regulators[id].enable_bit) != 0; +} + +static struct regulator_ops mc13783_gpo_regulator_ops = { +	.enable = mc13783_gpo_regulator_enable, +	.disable = mc13783_gpo_regulator_disable, +	.is_enabled = mc13783_gpo_regulator_is_enabled, +	.list_voltage = mc13783_regulator_list_voltage, +	.set_voltage = mc13783_fixed_regulator_set_voltage, +	.get_voltage = mc13783_fixed_regulator_get_voltage,  };  static int __devinit mc13783_regulator_probe(struct platform_device *pdev) diff --git a/drivers/regulator/pcap-regulator.c b/drivers/regulator/pcap-regulator.c index 33d7d899e030..29d0566379ae 100644 --- a/drivers/regulator/pcap-regulator.c +++ b/drivers/regulator/pcap-regulator.c @@ -288,16 +288,18 @@ static int __devexit pcap_regulator_remove(struct platform_device *pdev)  	struct regulator_dev *rdev = platform_get_drvdata(pdev);  	regulator_unregister(rdev); +	platform_set_drvdata(pdev, NULL);  	return 0;  }  static struct platform_driver pcap_regulator_driver = {  	.driver = { -		.name = "pcap-regulator", +		.name	= "pcap-regulator", +		.owner	= THIS_MODULE,  	}, -	.probe = pcap_regulator_probe, -	.remove = __devexit_p(pcap_regulator_remove), +	.probe	= pcap_regulator_probe, +	.remove	= __devexit_p(pcap_regulator_remove),  };  static int __init pcap_regulator_init(void) diff --git a/drivers/regulator/tps65023-regulator.c b/drivers/regulator/tps65023-regulator.c index 07fda0a75adf..1f183543bdbd 100644 --- a/drivers/regulator/tps65023-regulator.c +++ b/drivers/regulator/tps65023-regulator.c @@ -457,8 +457,8 @@ static struct regulator_ops tps65023_ldo_ops = {  	.list_voltage = tps65023_ldo_list_voltage,  }; -static -int tps_65023_probe(struct i2c_client *client, const struct i2c_device_id *id) +static int __devinit tps_65023_probe(struct i2c_client *client, +				     const struct i2c_device_id *id)  {  	static int desc_id;  	const struct tps_info *info = (void *)id->driver_data; @@ -466,6 +466,7 @@ int tps_65023_probe(struct i2c_client *client, const struct i2c_device_id *id)  	struct regulator_dev *rdev;  	struct tps_pmic *tps;  	int i; +	int error;  	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))  		return -EIO; @@ -475,7 +476,6 @@ int tps_65023_probe(struct i2c_client *client, const struct i2c_device_id *id)  	 * coming from the board-evm file.  	 */  	init_data = client->dev.platform_data; -  	if (!init_data)  		return -EIO; @@ -502,21 +502,12 @@ int tps_65023_probe(struct i2c_client *client, const struct i2c_device_id *id)  		/* Register the regulators */  		rdev = regulator_register(&tps->desc[i], &client->dev, -								init_data, tps); +					  init_data, tps);  		if (IS_ERR(rdev)) {  			dev_err(&client->dev, "failed to register %s\n",  				id->name); - -			/* Unregister */ -			while (i) -				regulator_unregister(tps->rdev[--i]); - -			tps->client = NULL; - -			/* clear the client data in i2c */ -			i2c_set_clientdata(client, NULL); -			kfree(tps); -			return PTR_ERR(rdev); +			error = PTR_ERR(rdev); +			goto fail;  		}  		/* Save regulator for cleanup */ @@ -526,6 +517,13 @@ int tps_65023_probe(struct i2c_client *client, const struct i2c_device_id *id)  	i2c_set_clientdata(client, tps);  	return 0; + + fail: +	while (--i >= 0) +		regulator_unregister(tps->rdev[i]); + +	kfree(tps); +	return error;  }  /** @@ -539,13 +537,12 @@ static int __devexit tps_65023_remove(struct i2c_client *client)  	struct tps_pmic *tps = i2c_get_clientdata(client);  	int i; +	/* clear the client data in i2c */ +	i2c_set_clientdata(client, NULL); +  	for (i = 0; i < TPS65023_NUM_REGULATOR; i++)  		regulator_unregister(tps->rdev[i]); -	tps->client = NULL; - -	/* clear the client data in i2c */ -	i2c_set_clientdata(client, NULL);  	kfree(tps);  	return 0; diff --git a/drivers/regulator/tps6507x-regulator.c b/drivers/regulator/tps6507x-regulator.c index f8a6dfbef751..c2a9539acd72 100644 --- a/drivers/regulator/tps6507x-regulator.c +++ b/drivers/regulator/tps6507x-regulator.c @@ -538,8 +538,8 @@ static struct regulator_ops tps6507x_ldo_ops = {  	.list_voltage = tps6507x_ldo_list_voltage,  }; -static -int tps_6507x_probe(struct i2c_client *client, const struct i2c_device_id *id) +static int __devinit tps_6507x_probe(struct i2c_client *client, +				     const struct i2c_device_id *id)  {  	static int desc_id;  	const struct tps_info *info = (void *)id->driver_data; @@ -547,6 +547,7 @@ int tps_6507x_probe(struct i2c_client *client, const struct i2c_device_id *id)  	struct regulator_dev *rdev;  	struct tps_pmic *tps;  	int i; +	int error;  	if (!i2c_check_functionality(client->adapter,  				I2C_FUNC_SMBUS_BYTE_DATA)) @@ -557,7 +558,6 @@ int tps_6507x_probe(struct i2c_client *client, const struct i2c_device_id *id)  	 * coming from the board-evm file.  	 */  	init_data = client->dev.platform_data; -  	if (!init_data)  		return -EIO; @@ -586,18 +586,8 @@ int tps_6507x_probe(struct i2c_client *client, const struct i2c_device_id *id)  		if (IS_ERR(rdev)) {  			dev_err(&client->dev, "failed to register %s\n",  				id->name); - -			/* Unregister */ -			while (i) -				regulator_unregister(tps->rdev[--i]); - -			tps->client = NULL; - -			/* clear the client data in i2c */ -			i2c_set_clientdata(client, NULL); - -			kfree(tps); -			return PTR_ERR(rdev); +			error = PTR_ERR(rdev); +			goto fail;  		}  		/* Save regulator for cleanup */ @@ -607,6 +597,13 @@ int tps_6507x_probe(struct i2c_client *client, const struct i2c_device_id *id)  	i2c_set_clientdata(client, tps);  	return 0; + +fail: +	while (--i >= 0) +		regulator_unregister(tps->rdev[i]); + +	kfree(tps); +	return error;  }  /** @@ -620,13 +617,12 @@ static int __devexit tps_6507x_remove(struct i2c_client *client)  	struct tps_pmic *tps = i2c_get_clientdata(client);  	int i; +	/* clear the client data in i2c */ +	i2c_set_clientdata(client, NULL); +  	for (i = 0; i < TPS6507X_NUM_REGULATOR; i++)  		regulator_unregister(tps->rdev[i]); -	tps->client = NULL; - -	/* clear the client data in i2c */ -	i2c_set_clientdata(client, NULL);  	kfree(tps);  	return 0; diff --git a/drivers/regulator/twl-regulator.c b/drivers/regulator/twl-regulator.c index 7e674859bd59..9729d760fb4d 100644 --- a/drivers/regulator/twl-regulator.c +++ b/drivers/regulator/twl-regulator.c @@ -519,19 +519,19 @@ 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, 1, 0, 0x08), -	TWL6030_ADJUSTABLE_LDO(VAUX2_6030, 0x58, 2, 0, 0x08), -	TWL6030_ADJUSTABLE_LDO(VAUX3_6030, 0x5c, 3, 0, 0x08), -	TWL6030_ADJUSTABLE_LDO(VMMC, 0x68, 4, 0, 0x08), -	TWL6030_ADJUSTABLE_LDO(VPP, 0x6c, 5, 0, 0x08), -	TWL6030_ADJUSTABLE_LDO(VUSIM, 0x74, 7, 0, 0x08), -	TWL6030_FIXED_LDO(VANA, 0x50, 2100, 15, 0, 0x08), -	TWL6030_FIXED_LDO(VCXIO, 0x60, 1800, 16, 0, 0x08), -	TWL6030_FIXED_LDO(VDAC, 0x64, 1800, 17, 0, 0x08), -	TWL6030_FIXED_LDO(VUSB, 0x70, 3300, 18, 0, 0x08) +	TWL6030_ADJUSTABLE_LDO(VAUX1_6030, 0x54, 1, 0, 0x21), +	TWL6030_ADJUSTABLE_LDO(VAUX2_6030, 0x58, 2, 0, 0x21), +	TWL6030_ADJUSTABLE_LDO(VAUX3_6030, 0x5c, 3, 0, 0x21), +	TWL6030_ADJUSTABLE_LDO(VMMC, 0x68, 4, 0, 0x21), +	TWL6030_ADJUSTABLE_LDO(VPP, 0x6c, 5, 0, 0x21), +	TWL6030_ADJUSTABLE_LDO(VUSIM, 0x74, 7, 0, 0x21), +	TWL6030_FIXED_LDO(VANA, 0x50, 2100, 15, 0, 0x21), +	TWL6030_FIXED_LDO(VCXIO, 0x60, 1800, 16, 0, 0x21), +	TWL6030_FIXED_LDO(VDAC, 0x64, 1800, 17, 0, 0x21), +	TWL6030_FIXED_LDO(VUSB, 0x70, 3300, 18, 0, 0x21)  }; -static int twlreg_probe(struct platform_device *pdev) +static int __devinit twlreg_probe(struct platform_device *pdev)  {  	int				i;  	struct twlreg_info		*info; diff --git a/drivers/regulator/virtual.c b/drivers/regulator/virtual.c index addc032c84bf..d96cecaac73d 100644 --- a/drivers/regulator/virtual.c +++ b/drivers/regulator/virtual.c @@ -19,7 +19,7 @@  struct virtual_consumer_data {  	struct mutex lock;  	struct regulator *regulator; -	int enabled; +	bool enabled;  	int min_uV;  	int max_uV;  	int min_uA; @@ -49,7 +49,7 @@ static void update_voltage_constraints(struct device *dev,  		dev_dbg(dev, "Enabling regulator\n");  		ret = regulator_enable(data->regulator);  		if (ret == 0) -			data->enabled = 1; +			data->enabled = true;  		else  			dev_err(dev, "regulator_enable() failed: %d\n",  				ret); @@ -59,7 +59,7 @@ static void update_voltage_constraints(struct device *dev,  		dev_dbg(dev, "Disabling regulator\n");  		ret = regulator_disable(data->regulator);  		if (ret == 0) -			data->enabled = 0; +			data->enabled = false;  		else  			dev_err(dev, "regulator_disable() failed: %d\n",  				ret); @@ -89,7 +89,7 @@ static void update_current_limit_constraints(struct device *dev,  		dev_dbg(dev, "Enabling regulator\n");  		ret = regulator_enable(data->regulator);  		if (ret == 0) -			data->enabled = 1; +			data->enabled = true;  		else  			dev_err(dev, "regulator_enable() failed: %d\n",  				ret); @@ -99,7 +99,7 @@ static void update_current_limit_constraints(struct device *dev,  		dev_dbg(dev, "Disabling regulator\n");  		ret = regulator_disable(data->regulator);  		if (ret == 0) -			data->enabled = 0; +			data->enabled = false;  		else  			dev_err(dev, "regulator_disable() failed: %d\n",  				ret); @@ -270,24 +270,28 @@ static DEVICE_ATTR(min_microamps, 0666, show_min_uA, set_min_uA);  static DEVICE_ATTR(max_microamps, 0666, show_max_uA, set_max_uA);  static DEVICE_ATTR(mode, 0666, show_mode, set_mode); -static struct device_attribute *attributes[] = { -	&dev_attr_min_microvolts, -	&dev_attr_max_microvolts, -	&dev_attr_min_microamps, -	&dev_attr_max_microamps, -	&dev_attr_mode, +static struct attribute *regulator_virtual_attributes[] = { +	&dev_attr_min_microvolts.attr, +	&dev_attr_max_microvolts.attr, +	&dev_attr_min_microamps.attr, +	&dev_attr_max_microamps.attr, +	&dev_attr_mode.attr, +	NULL  }; -static int regulator_virtual_consumer_probe(struct platform_device *pdev) +static const struct attribute_group regulator_virtual_attr_group = { +	.attrs	= regulator_virtual_attributes, +}; + +static int __devinit regulator_virtual_probe(struct platform_device *pdev)  {  	char *reg_id = pdev->dev.platform_data;  	struct virtual_consumer_data *drvdata; -	int ret, i; +	int ret;  	drvdata = kzalloc(sizeof(struct virtual_consumer_data), GFP_KERNEL); -	if (drvdata == NULL) { +	if (drvdata == NULL)  		return -ENOMEM; -	}  	mutex_init(&drvdata->lock); @@ -299,13 +303,12 @@ static int regulator_virtual_consumer_probe(struct platform_device *pdev)  		goto err;  	} -	for (i = 0; i < ARRAY_SIZE(attributes); i++) { -		ret = device_create_file(&pdev->dev, attributes[i]); -		if (ret != 0) { -			dev_err(&pdev->dev, "Failed to create attr %d: %d\n", -				i, ret); -			goto err_regulator; -		} +	ret = sysfs_create_group(&pdev->dev.kobj, +				 ®ulator_virtual_attr_group); +	if (ret != 0) { +		dev_err(&pdev->dev, +			"Failed to create attribute group: %d\n", ret); +		goto err_regulator;  	}  	drvdata->mode = regulator_get_mode(drvdata->regulator); @@ -317,37 +320,36 @@ static int regulator_virtual_consumer_probe(struct platform_device *pdev)  err_regulator:  	regulator_put(drvdata->regulator);  err: -	for (i = 0; i < ARRAY_SIZE(attributes); i++) -		device_remove_file(&pdev->dev, attributes[i]);  	kfree(drvdata);  	return ret;  } -static int regulator_virtual_consumer_remove(struct platform_device *pdev) +static int __devexit regulator_virtual_remove(struct platform_device *pdev)  {  	struct virtual_consumer_data *drvdata = platform_get_drvdata(pdev); -	int i; -	for (i = 0; i < ARRAY_SIZE(attributes); i++) -		device_remove_file(&pdev->dev, attributes[i]); +	sysfs_remove_group(&pdev->dev.kobj, ®ulator_virtual_attr_group); +  	if (drvdata->enabled)  		regulator_disable(drvdata->regulator);  	regulator_put(drvdata->regulator);  	kfree(drvdata); +	platform_set_drvdata(pdev, NULL); +  	return 0;  }  static struct platform_driver regulator_virtual_consumer_driver = { -	.probe		= regulator_virtual_consumer_probe, -	.remove		= regulator_virtual_consumer_remove, +	.probe		= regulator_virtual_probe, +	.remove		= __devexit_p(regulator_virtual_remove),  	.driver		= {  		.name		= "reg-virt-consumer", +		.owner		= THIS_MODULE,  	},  }; -  static int __init regulator_virtual_consumer_init(void)  {  	return platform_driver_register(®ulator_virtual_consumer_driver); diff --git a/drivers/regulator/wm831x-dcdc.c b/drivers/regulator/wm831x-dcdc.c index 0a6577577e8d..6e18e56d850b 100644 --- a/drivers/regulator/wm831x-dcdc.c +++ b/drivers/regulator/wm831x-dcdc.c @@ -600,6 +600,8 @@ static __devexit int wm831x_buckv_remove(struct platform_device *pdev)  	struct wm831x_dcdc *dcdc = platform_get_drvdata(pdev);  	struct wm831x *wm831x = dcdc->wm831x; +	platform_set_drvdata(pdev, NULL); +  	wm831x_free_irq(wm831x, platform_get_irq_byname(pdev, "HC"), dcdc);  	wm831x_free_irq(wm831x, platform_get_irq_byname(pdev, "UV"), dcdc);  	regulator_unregister(dcdc->regulator); @@ -615,6 +617,7 @@ static struct platform_driver wm831x_buckv_driver = {  	.remove = __devexit_p(wm831x_buckv_remove),  	.driver		= {  		.name	= "wm831x-buckv", +		.owner	= THIS_MODULE,  	},  }; @@ -769,6 +772,8 @@ static __devexit int wm831x_buckp_remove(struct platform_device *pdev)  	struct wm831x_dcdc *dcdc = platform_get_drvdata(pdev);  	struct wm831x *wm831x = dcdc->wm831x; +	platform_set_drvdata(pdev, NULL); +  	wm831x_free_irq(wm831x, platform_get_irq_byname(pdev, "UV"), dcdc);  	regulator_unregister(dcdc->regulator);  	kfree(dcdc); @@ -781,6 +786,7 @@ static struct platform_driver wm831x_buckp_driver = {  	.remove = __devexit_p(wm831x_buckp_remove),  	.driver		= {  		.name	= "wm831x-buckp", +		.owner	= THIS_MODULE,  	},  }; @@ -895,6 +901,8 @@ static __devexit int wm831x_boostp_remove(struct platform_device *pdev)  	struct wm831x_dcdc *dcdc = platform_get_drvdata(pdev);  	struct wm831x *wm831x = dcdc->wm831x; +	platform_set_drvdata(pdev, NULL); +  	wm831x_free_irq(wm831x, platform_get_irq_byname(pdev, "UV"), dcdc);  	regulator_unregister(dcdc->regulator);  	kfree(dcdc); @@ -907,6 +915,7 @@ static struct platform_driver wm831x_boostp_driver = {  	.remove = __devexit_p(wm831x_boostp_remove),  	.driver		= {  		.name	= "wm831x-boostp", +		.owner	= THIS_MODULE,  	},  }; @@ -979,6 +988,8 @@ static __devexit int wm831x_epe_remove(struct platform_device *pdev)  {  	struct wm831x_dcdc *dcdc = platform_get_drvdata(pdev); +	platform_set_drvdata(pdev, NULL); +  	regulator_unregister(dcdc->regulator);  	kfree(dcdc); @@ -990,6 +1001,7 @@ static struct platform_driver wm831x_epe_driver = {  	.remove = __devexit_p(wm831x_epe_remove),  	.driver		= {  		.name	= "wm831x-epe", +		.owner	= THIS_MODULE,  	},  }; diff --git a/drivers/regulator/wm831x-isink.c b/drivers/regulator/wm831x-isink.c index 48857008758c..ca0f6b6c384b 100644 --- a/drivers/regulator/wm831x-isink.c +++ b/drivers/regulator/wm831x-isink.c @@ -222,6 +222,8 @@ static __devexit int wm831x_isink_remove(struct platform_device *pdev)  	struct wm831x_isink *isink = platform_get_drvdata(pdev);  	struct wm831x *wm831x = isink->wm831x; +	platform_set_drvdata(pdev, NULL); +  	wm831x_free_irq(wm831x, platform_get_irq(pdev, 0), isink);  	regulator_unregister(isink->regulator); @@ -235,6 +237,7 @@ static struct platform_driver wm831x_isink_driver = {  	.remove = __devexit_p(wm831x_isink_remove),  	.driver		= {  		.name	= "wm831x-isink", +		.owner	= THIS_MODULE,  	},  }; diff --git a/drivers/regulator/wm831x-ldo.c b/drivers/regulator/wm831x-ldo.c index 61e02ac2fda3..d2406c1519a1 100644 --- a/drivers/regulator/wm831x-ldo.c +++ b/drivers/regulator/wm831x-ldo.c @@ -371,6 +371,8 @@ static __devexit int wm831x_gp_ldo_remove(struct platform_device *pdev)  	struct wm831x_ldo *ldo = platform_get_drvdata(pdev);  	struct wm831x *wm831x = ldo->wm831x; +	platform_set_drvdata(pdev, NULL); +  	wm831x_free_irq(wm831x, platform_get_irq_byname(pdev, "UV"), ldo);  	regulator_unregister(ldo->regulator);  	kfree(ldo); @@ -383,6 +385,7 @@ static struct platform_driver wm831x_gp_ldo_driver = {  	.remove = __devexit_p(wm831x_gp_ldo_remove),  	.driver		= {  		.name	= "wm831x-ldo", +		.owner	= THIS_MODULE,  	},  }; @@ -640,6 +643,7 @@ static struct platform_driver wm831x_aldo_driver = {  	.remove = __devexit_p(wm831x_aldo_remove),  	.driver		= {  		.name	= "wm831x-aldo", +		.owner	= THIS_MODULE,  	},  }; @@ -811,6 +815,7 @@ static struct platform_driver wm831x_alive_ldo_driver = {  	.remove = __devexit_p(wm831x_alive_ldo_remove),  	.driver		= {  		.name	= "wm831x-alive-ldo", +		.owner	= THIS_MODULE,  	},  }; diff --git a/drivers/regulator/wm8350-regulator.c b/drivers/regulator/wm8350-regulator.c index e7b89e704af6..94227dd6ba7b 100644 --- a/drivers/regulator/wm8350-regulator.c +++ b/drivers/regulator/wm8350-regulator.c @@ -290,6 +290,51 @@ static int wm8350_isink_is_enabled(struct regulator_dev *rdev)  	return -EINVAL;  } +static int wm8350_isink_enable_time(struct regulator_dev *rdev) +{ +	struct wm8350 *wm8350 = rdev_get_drvdata(rdev); +	int isink = rdev_get_id(rdev); +	int reg; + +	switch (isink) { +	case WM8350_ISINK_A: +		reg = wm8350_reg_read(wm8350, WM8350_CSA_FLASH_CONTROL); +		break; +	case WM8350_ISINK_B: +		reg = wm8350_reg_read(wm8350, WM8350_CSB_FLASH_CONTROL); +		break; +	default: +		return -EINVAL; +	} + +	if (reg & WM8350_CS1_FLASH_MODE) { +		switch (reg & WM8350_CS1_ON_RAMP_MASK) { +		case 0: +			return 0; +		case 1: +			return 1950; +		case 2: +			return 3910; +		case 3: +			return 7800; +		} +	} else { +		switch (reg & WM8350_CS1_ON_RAMP_MASK) { +		case 0: +			return 0; +		case 1: +			return 250000; +		case 2: +			return 500000; +		case 3: +			return 1000000; +		} +	} + +	return -EINVAL; +} + +  int wm8350_isink_set_flash(struct wm8350 *wm8350, int isink, u16 mode,  			   u16 trigger, u16 duration, u16 on_ramp, u16 off_ramp,  			   u16 drive) @@ -1221,6 +1266,7 @@ static struct regulator_ops wm8350_isink_ops = {  	.enable = wm8350_isink_enable,  	.disable = wm8350_isink_disable,  	.is_enabled = wm8350_isink_is_enabled, +	.enable_time = wm8350_isink_enable_time,  };  static struct regulator_desc wm8350_reg[NUM_WM8350_REGULATORS] = { diff --git a/drivers/regulator/wm8400-regulator.c b/drivers/regulator/wm8400-regulator.c index d9a2c988c6e7..924c7eb29ee9 100644 --- a/drivers/regulator/wm8400-regulator.c +++ b/drivers/regulator/wm8400-regulator.c @@ -317,14 +317,17 @@ static struct regulator_desc regulators[] = {  static int __devinit wm8400_regulator_probe(struct platform_device *pdev)  { +	struct wm8400 *wm8400 = container_of(pdev, struct wm8400, regulators[pdev->id]);  	struct regulator_dev *rdev;  	rdev = regulator_register(®ulators[pdev->id], &pdev->dev, -		pdev->dev.platform_data, dev_get_drvdata(&pdev->dev)); +				  pdev->dev.platform_data, wm8400);  	if (IS_ERR(rdev))  		return PTR_ERR(rdev); +	platform_set_drvdata(pdev, rdev); +  	return 0;  } @@ -332,6 +335,7 @@ static int __devexit wm8400_regulator_remove(struct platform_device *pdev)  {  	struct regulator_dev *rdev = platform_get_drvdata(pdev); +	platform_set_drvdata(pdev, NULL);  	regulator_unregister(rdev);  	return 0; @@ -370,7 +374,6 @@ int wm8400_register_regulator(struct device *dev, int reg,  	wm8400->regulators[reg].id = reg;  	wm8400->regulators[reg].dev.parent = dev;  	wm8400->regulators[reg].dev.platform_data = initdata; -	dev_set_drvdata(&wm8400->regulators[reg].dev, wm8400);  	return platform_device_register(&wm8400->regulators[reg]);  } diff --git a/drivers/regulator/wm8994-regulator.c b/drivers/regulator/wm8994-regulator.c new file mode 100644 index 000000000000..95454a4637b7 --- /dev/null +++ b/drivers/regulator/wm8994-regulator.c @@ -0,0 +1,307 @@ +/* + * wm8994-regulator.c  --  Regulator driver for the WM8994 + * + * Copyright 2009 Wolfson Microelectronics PLC. + * + * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> + * + *  This program is free software; you can redistribute  it and/or modify it + *  under  the terms of  the GNU General  Public License as published by the + *  Free Software Foundation;  either version 2 of the  License, or (at your + *  option) any later version. + */ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/init.h> +#include <linux/bitops.h> +#include <linux/err.h> +#include <linux/platform_device.h> +#include <linux/regulator/driver.h> +#include <linux/gpio.h> + +#include <linux/mfd/wm8994/core.h> +#include <linux/mfd/wm8994/registers.h> +#include <linux/mfd/wm8994/pdata.h> + +struct wm8994_ldo { +	int enable; +	bool is_enabled; +	struct regulator_dev *regulator; +	struct wm8994 *wm8994; +}; + +#define WM8994_LDO1_MAX_SELECTOR 0x7 +#define WM8994_LDO2_MAX_SELECTOR 0x3 + +static int wm8994_ldo_enable(struct regulator_dev *rdev) +{ +	struct wm8994_ldo *ldo = rdev_get_drvdata(rdev); + +	/* If we have no soft control assume that the LDO is always enabled. */ +	if (!ldo->enable) +		return 0; + +	gpio_set_value(ldo->enable, 1); +	ldo->is_enabled = true; + +	return 0; +} + +static int wm8994_ldo_disable(struct regulator_dev *rdev) +{ +	struct wm8994_ldo *ldo = rdev_get_drvdata(rdev); + +	/* If we have no soft control assume that the LDO is always enabled. */ +	if (!ldo->enable) +		return -EINVAL; + +	gpio_set_value(ldo->enable, 0); +	ldo->is_enabled = false; + +	return 0; +} + +static int wm8994_ldo_is_enabled(struct regulator_dev *rdev) +{ +	struct wm8994_ldo *ldo = rdev_get_drvdata(rdev); + +	return ldo->is_enabled; +} + +static int wm8994_ldo_enable_time(struct regulator_dev *rdev) +{ +	/* 3ms is fairly conservative but this shouldn't be too performance +	 * critical; can be tweaked per-system if required. */ +	return 3000; +} + +static int wm8994_ldo1_list_voltage(struct regulator_dev *rdev, +				    unsigned int selector) +{ +	if (selector > WM8994_LDO1_MAX_SELECTOR) +		return -EINVAL; + +	return (selector * 100000) + 2400000; +} + +static int wm8994_ldo1_get_voltage(struct regulator_dev *rdev) +{ +	struct wm8994_ldo *ldo = rdev_get_drvdata(rdev); +	int val; + +	val = wm8994_reg_read(ldo->wm8994, WM8994_LDO_1); +	if (val < 0) +		return val; + +	val = (val & WM8994_LDO1_VSEL_MASK) >> WM8994_LDO1_VSEL_SHIFT; + +	return wm8994_ldo1_list_voltage(rdev, val); +} + +static int wm8994_ldo1_set_voltage(struct regulator_dev *rdev, +				   int min_uV, int max_uV) +{ +	struct wm8994_ldo *ldo = rdev_get_drvdata(rdev); +	int selector, v; + +	selector = (min_uV - 2400000) / 100000; +	v = wm8994_ldo1_list_voltage(rdev, selector); +	if (v < 0 || v > max_uV) +		return -EINVAL; + +	selector <<= WM8994_LDO1_VSEL_SHIFT; + +	return wm8994_set_bits(ldo->wm8994, WM8994_LDO_1, +			       WM8994_LDO1_VSEL_MASK, selector); +} + +static struct regulator_ops wm8994_ldo1_ops = { +	.enable = wm8994_ldo_enable, +	.disable = wm8994_ldo_disable, +	.is_enabled = wm8994_ldo_is_enabled, +	.enable_time = wm8994_ldo_enable_time, + +	.list_voltage = wm8994_ldo1_list_voltage, +	.get_voltage = wm8994_ldo1_get_voltage, +	.set_voltage = wm8994_ldo1_set_voltage, +}; + +static int wm8994_ldo2_list_voltage(struct regulator_dev *rdev, +				    unsigned int selector) +{ +	if (selector > WM8994_LDO2_MAX_SELECTOR) +		return -EINVAL; + +	return (selector * 100000) + 900000; +} + +static int wm8994_ldo2_get_voltage(struct regulator_dev *rdev) +{ +	struct wm8994_ldo *ldo = rdev_get_drvdata(rdev); +	int val; + +	val = wm8994_reg_read(ldo->wm8994, WM8994_LDO_2); +	if (val < 0) +		return val; + +	val = (val & WM8994_LDO2_VSEL_MASK) >> WM8994_LDO2_VSEL_SHIFT; + +	return wm8994_ldo2_list_voltage(rdev, val); +} + +static int wm8994_ldo2_set_voltage(struct regulator_dev *rdev, +				   int min_uV, int max_uV) +{ +	struct wm8994_ldo *ldo = rdev_get_drvdata(rdev); +	int selector, v; + +	selector = (min_uV - 900000) / 100000; +	v = wm8994_ldo2_list_voltage(rdev, selector); +	if (v < 0 || v > max_uV) +		return -EINVAL; + +	selector <<= WM8994_LDO2_VSEL_SHIFT; + +	return wm8994_set_bits(ldo->wm8994, WM8994_LDO_2, +			       WM8994_LDO2_VSEL_MASK, selector); +} + +static struct regulator_ops wm8994_ldo2_ops = { +	.enable = wm8994_ldo_enable, +	.disable = wm8994_ldo_disable, +	.is_enabled = wm8994_ldo_is_enabled, +	.enable_time = wm8994_ldo_enable_time, + +	.list_voltage = wm8994_ldo2_list_voltage, +	.get_voltage = wm8994_ldo2_get_voltage, +	.set_voltage = wm8994_ldo2_set_voltage, +}; + +static struct regulator_desc wm8994_ldo_desc[] = { +	{ +		.name = "LDO1", +		.id = 1, +		.type = REGULATOR_VOLTAGE, +		.n_voltages = WM8994_LDO1_MAX_SELECTOR + 1, +		.ops = &wm8994_ldo1_ops, +		.owner = THIS_MODULE, +	}, +	{ +		.name = "LDO2", +		.id = 2, +		.type = REGULATOR_VOLTAGE, +		.n_voltages = WM8994_LDO2_MAX_SELECTOR + 1, +		.ops = &wm8994_ldo2_ops, +		.owner = THIS_MODULE, +	}, +}; + +static __devinit int wm8994_ldo_probe(struct platform_device *pdev) +{ +	struct wm8994 *wm8994 = dev_get_drvdata(pdev->dev.parent); +	struct wm8994_pdata *pdata = wm8994->dev->platform_data; +	int id = pdev->id % ARRAY_SIZE(pdata->ldo); +	struct wm8994_ldo *ldo; +	int ret; + +	dev_dbg(&pdev->dev, "Probing LDO%d\n", id + 1); + +	if (!pdata) +		return -ENODEV; + +	ldo = kzalloc(sizeof(struct wm8994_ldo), GFP_KERNEL); +	if (ldo == NULL) { +		dev_err(&pdev->dev, "Unable to allocate private data\n"); +		return -ENOMEM; +	} + +	ldo->wm8994 = wm8994; + +	ldo->is_enabled = true; + +	if (pdata->ldo[id].enable && gpio_is_valid(pdata->ldo[id].enable)) { +		ldo->enable = pdata->ldo[id].enable; + +		ret = gpio_request(ldo->enable, "WM8994 LDO enable"); +		if (ret < 0) { +			dev_err(&pdev->dev, "Failed to get enable GPIO: %d\n", +				ret); +			goto err; +		} + +		ret = gpio_direction_output(ldo->enable, ldo->is_enabled); +		if (ret < 0) { +			dev_err(&pdev->dev, "Failed to set GPIO up: %d\n", +				ret); +			goto err_gpio; +		} +	} + +	ldo->regulator = regulator_register(&wm8994_ldo_desc[id], &pdev->dev, +					     pdata->ldo[id].init_data, ldo); +	if (IS_ERR(ldo->regulator)) { +		ret = PTR_ERR(ldo->regulator); +		dev_err(wm8994->dev, "Failed to register LDO%d: %d\n", +			id + 1, ret); +		goto err_gpio; +	} + +	platform_set_drvdata(pdev, ldo); + +	return 0; + +err_gpio: +	if (gpio_is_valid(ldo->enable)) +		gpio_free(ldo->enable); +err: +	kfree(ldo); +	return ret; +} + +static __devexit int wm8994_ldo_remove(struct platform_device *pdev) +{ +	struct wm8994_ldo *ldo = platform_get_drvdata(pdev); + +	platform_set_drvdata(pdev, NULL); + +	regulator_unregister(ldo->regulator); +	if (gpio_is_valid(ldo->enable)) +		gpio_free(ldo->enable); +	kfree(ldo); + +	return 0; +} + +static struct platform_driver wm8994_ldo_driver = { +	.probe = wm8994_ldo_probe, +	.remove = __devexit_p(wm8994_ldo_remove), +	.driver		= { +		.name	= "wm8994-ldo", +		.owner	= THIS_MODULE, +	}, +}; + +static int __init wm8994_ldo_init(void) +{ +	int ret; + +	ret = platform_driver_register(&wm8994_ldo_driver); +	if (ret != 0) +		pr_err("Failed to register Wm8994 GP LDO driver: %d\n", ret); + +	return ret; +} +subsys_initcall(wm8994_ldo_init); + +static void __exit wm8994_ldo_exit(void) +{ +	platform_driver_unregister(&wm8994_ldo_driver); +} +module_exit(wm8994_ldo_exit); + +/* Module information */ +MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); +MODULE_DESCRIPTION("WM8994 LDO driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:wm8994-ldo"); diff --git a/include/linux/mfd/mc13783.h b/include/linux/mfd/mc13783.h index 35680409b8cf..94cb51a64037 100644 --- a/include/linux/mfd/mc13783.h +++ b/include/linux/mfd/mc13783.h @@ -108,6 +108,8 @@ int mc13783_adc_do_conversion(struct mc13783 *mc13783, unsigned int mode,  #define	MC13783_REGU_V2		28  #define	MC13783_REGU_V3		29  #define	MC13783_REGU_V4		30 +#define	MC13783_REGU_PWGT1SPI	31 +#define	MC13783_REGU_PWGT2SPI	32  #define MC13783_IRQ_ADCDONE	0  #define MC13783_IRQ_ADCBISDONE	1 diff --git a/include/linux/regulator/consumer.h b/include/linux/regulator/consumer.h index 030d92255c7a..28c9fd020d39 100644 --- a/include/linux/regulator/consumer.h +++ b/include/linux/regulator/consumer.h @@ -89,8 +89,9 @@   * REGULATION_OUT Regulator output is out of regulation.   * FAIL           Regulator output has failed.   * OVER_TEMP      Regulator over temp. - * FORCE_DISABLE  Regulator shut down by software. + * FORCE_DISABLE  Regulator forcibly shut down by software.   * VOLTAGE_CHANGE Regulator voltage changed. + * DISABLE        Regulator was disabled.   *   * NOTE: These events can be OR'ed together when passed into handler.   */ @@ -102,6 +103,7 @@  #define REGULATOR_EVENT_OVER_TEMP		0x10  #define REGULATOR_EVENT_FORCE_DISABLE		0x20  #define REGULATOR_EVENT_VOLTAGE_CHANGE		0x40 +#define REGULATOR_EVENT_DISABLE 		0x80  struct regulator; diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h index 31f2055eae28..592cd7c642c2 100644 --- a/include/linux/regulator/driver.h +++ b/include/linux/regulator/driver.h @@ -58,6 +58,9 @@ enum regulator_status {   * @get_optimum_mode: Get the most efficient operating mode for the regulator   *                    when running with the specified parameters.   * + * @enable_time: Time taken for the regulator voltage output voltage to + *               stabalise after being enabled, in microseconds. + *   * @set_suspend_voltage: Set the voltage for the regulator when the system   *                       is suspended.   * @set_suspend_enable: Mark the regulator as enabled when the system is @@ -93,6 +96,9 @@ struct regulator_ops {  	int (*set_mode) (struct regulator_dev *, unsigned int mode);  	unsigned int (*get_mode) (struct regulator_dev *); +	/* Time taken to enable the regulator */ +	int (*enable_time) (struct regulator_dev *); +  	/* report regulator status ... most other accessors report  	 * control inputs, this reports results of combining inputs  	 * from Linux (and other sources) with the actual load. diff --git a/include/linux/regulator/fixed.h b/include/linux/regulator/fixed.h index e94a4a1c7c8a..ffd7d508e726 100644 --- a/include/linux/regulator/fixed.h +++ b/include/linux/regulator/fixed.h @@ -25,6 +25,7 @@ struct regulator_init_data;   * @microvolts:		Output voltage of regulator   * @gpio:		GPIO to use for enable control   * 			set to -EINVAL if not used + * @startup_delay:	Start-up time in microseconds   * @enable_high:	Polarity of enable GPIO   *			1 = Active high, 0 = Active low   * @enabled_at_boot:	Whether regulator has been enabled at @@ -41,6 +42,7 @@ struct fixed_voltage_config {  	const char *supply_name;  	int microvolts;  	int gpio; +	unsigned startup_delay;  	unsigned enable_high:1;  	unsigned enabled_at_boot:1;  	struct regulator_init_data *init_data; diff --git a/include/linux/regulator/max8649.h b/include/linux/regulator/max8649.h new file mode 100644 index 000000000000..417d14ecd5cb --- /dev/null +++ b/include/linux/regulator/max8649.h @@ -0,0 +1,44 @@ +/* + * Interface of Maxim max8649 + * + * Copyright (C) 2009-2010 Marvell International Ltd. + *      Haojian Zhuang <haojian.zhuang@marvell.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __LINUX_REGULATOR_MAX8649_H +#define	__LINUX_REGULATOR_MAX8649_H + +#include <linux/regulator/machine.h> + +enum { +	MAX8649_EXTCLK_26MHZ = 0, +	MAX8649_EXTCLK_13MHZ, +	MAX8649_EXTCLK_19MHZ,	/* 19.2MHz */ +}; + +enum { +	MAX8649_RAMP_32MV = 0, +	MAX8649_RAMP_16MV, +	MAX8649_RAMP_8MV, +	MAX8649_RAMP_4MV, +	MAX8649_RAMP_2MV, +	MAX8649_RAMP_1MV, +	MAX8649_RAMP_0_5MV, +	MAX8649_RAMP_0_25MV, +}; + +struct max8649_platform_data { +	struct regulator_init_data *regulator; + +	unsigned	mode:2;		/* bit[1:0] = VID1,VID0 */ +	unsigned	extclk_freq:2; +	unsigned	extclk:1; +	unsigned	ramp_timing:3; +	unsigned	ramp_down:1; +}; + +#endif	/* __LINUX_REGULATOR_MAX8649_H */ | 
