Commit fd8b327e authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/lrg/voltage-2.6

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/lrg/voltage-2.6: (41 commits)
  regulator: Add some brief design documentation
  regulator: fix voltage range in da9034 ldo12
  regulator/driver: be more specific in nanodoc for is_enabled
  regulator/lp3971: drop unnecessary initialization
  regulator: drop 'default n'
  regulator: fix typos
  regulator: fix calculation of voltage range in da9034_set_ldo12_voltage()
  regulator: update a filename in documentation
  drivers/regulator/Kconfig: fix typo (s/Usersapce/Userspace/) in REGULATOR_USERSPACE_CONSUMER description
  REGULATOR Handle positive returncode from enable
  regulator: tps650xx - build fixes for x86_64
  Fix some regulator documentation
  Regulator: Adding TPS65023 and TPS6507x in Kconfig and Makefile
  Regulator: Add TPS6507x regulator driver
  Regulator: Add TPS65023 regulator driver
  regulator: userspace: use sysfs_create_group
  regulator: Add GPIO enable control to fixed voltage regulator driver
  Regulator: Implement list_voltage for pcf50633 regulator driver.
  regulator: regulator_enable() permission checking
  regulator: Push locking for regulator_is_enabled() out
  ...
parents 0c9af280 63209a71
Regulator API design notes
==========================
This document provides a brief, partially structured, overview of some
of the design considerations which impact the regulator API design.
Safety
------
- Errors in regulator configuration can have very serious consequences
for the system, potentially including lasting hardware damage.
- It is not possible to automatically determine the power confugration
of the system - software-equivalent variants of the same chip may
have different power requirments, and not all components with power
requirements are visible to software.
=> The API should make no changes to the hardware state unless it has
specific knowledge that these changes are safe to do perform on
this particular system.
Consumer use cases
------------------
- The overwhelming majority of devices in a system will have no
requirement to do any runtime configuration of their power beyond
being able to turn it on or off.
- Many of the power supplies in the system will be shared between many
different consumers.
=> The consumer API should be structured so that these use cases are
very easy to handle and so that consumers will work with shared
supplies without any additional effort.
...@@ -87,7 +87,7 @@ static struct platform_device regulator_devices[] = { ...@@ -87,7 +87,7 @@ static struct platform_device regulator_devices[] = {
}, },
}; };
/* register regulator 1 device */ /* register regulator 1 device */
platform_device_register(&wm8350_regulator_devices[0]); platform_device_register(&regulator_devices[0]);
/* register regulator 2 device */ /* register regulator 2 device */
platform_device_register(&wm8350_regulator_devices[1]); platform_device_register(&regulator_devices[1]);
...@@ -29,7 +29,7 @@ Some terms used in this document:- ...@@ -29,7 +29,7 @@ Some terms used in this document:-
o PMIC - Power Management IC. An IC that contains numerous regulators o PMIC - Power Management IC. An IC that contains numerous regulators
and often contains other susbsystems. and often contains other subsystems.
o Consumer - Electronic device that is supplied power by a regulator. o Consumer - Electronic device that is supplied power by a regulator.
...@@ -168,4 +168,4 @@ relevant to non SoC devices and is split into the following four interfaces:- ...@@ -168,4 +168,4 @@ relevant to non SoC devices and is split into the following four interfaces:-
userspace via sysfs. This could be used to help monitor device power userspace via sysfs. This could be used to help monitor device power
consumption and status. consumption and status.
See Documentation/ABI/testing/regulator-sysfs.txt See Documentation/ABI/testing/sysfs-class-regulator
...@@ -10,8 +10,9 @@ Registration ...@@ -10,8 +10,9 @@ Registration
Drivers can register a regulator by calling :- Drivers can register a regulator by calling :-
struct regulator_dev *regulator_register(struct device *dev, struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc,
struct regulator_desc *regulator_desc); struct device *dev, struct regulator_init_data *init_data,
void *driver_data);
This will register the regulators capabilities and operations to the regulator This will register the regulators capabilities and operations to the regulator
core. core.
......
menuconfig REGULATOR menuconfig REGULATOR
bool "Voltage and Current Regulator Support" bool "Voltage and Current Regulator Support"
default n
help help
Generic Voltage and Current Regulator support. Generic Voltage and Current Regulator support.
...@@ -30,7 +29,6 @@ config REGULATOR_DEBUG ...@@ -30,7 +29,6 @@ config REGULATOR_DEBUG
config REGULATOR_FIXED_VOLTAGE config REGULATOR_FIXED_VOLTAGE
tristate "Fixed voltage regulator support" tristate "Fixed voltage regulator support"
default n
help help
This driver provides support for fixed voltage regulators, This driver provides support for fixed voltage regulators,
useful for systems which use a combination of software useful for systems which use a combination of software
...@@ -38,7 +36,6 @@ config REGULATOR_FIXED_VOLTAGE ...@@ -38,7 +36,6 @@ config REGULATOR_FIXED_VOLTAGE
config REGULATOR_VIRTUAL_CONSUMER config REGULATOR_VIRTUAL_CONSUMER
tristate "Virtual regulator consumer support" tristate "Virtual regulator consumer support"
default n
help help
This driver provides a virtual consumer for the voltage and This driver provides a virtual consumer for the voltage and
current regulator API which provides sysfs controls for current regulator API which provides sysfs controls for
...@@ -49,17 +46,15 @@ config REGULATOR_VIRTUAL_CONSUMER ...@@ -49,17 +46,15 @@ config REGULATOR_VIRTUAL_CONSUMER
config REGULATOR_USERSPACE_CONSUMER config REGULATOR_USERSPACE_CONSUMER
tristate "Userspace regulator consumer support" tristate "Userspace regulator consumer support"
default n
help help
There are some classes of devices that are controlled entirely There are some classes of devices that are controlled entirely
from user space. Usersapce consumer driver provides ability to from user space. Userspace consumer driver provides ability to
control power supplies for such devices. control power supplies for such devices.
If unsure, say no. If unsure, say no.
config REGULATOR_BQ24022 config REGULATOR_BQ24022
tristate "TI bq24022 Dual Input 1-Cell Li-Ion Charger IC" tristate "TI bq24022 Dual Input 1-Cell Li-Ion Charger IC"
default n
help help
This driver controls a TI bq24022 Charger attached via This driver controls a TI bq24022 Charger attached via
GPIOs. The provided current regulator can enable/disable GPIOs. The provided current regulator can enable/disable
...@@ -69,7 +64,6 @@ config REGULATOR_BQ24022 ...@@ -69,7 +64,6 @@ config REGULATOR_BQ24022
config REGULATOR_MAX1586 config REGULATOR_MAX1586
tristate "Maxim 1586/1587 voltage regulator" tristate "Maxim 1586/1587 voltage regulator"
depends on I2C depends on I2C
default n
help help
This driver controls a Maxim 1586 or 1587 voltage output This driver controls a Maxim 1586 or 1587 voltage output
regulator via I2C bus. The provided regulator is suitable regulator via I2C bus. The provided regulator is suitable
...@@ -147,5 +141,21 @@ config REGULATOR_AB3100 ...@@ -147,5 +141,21 @@ config REGULATOR_AB3100
AB3100 analog baseband dealing with power regulators AB3100 analog baseband dealing with power regulators
for the system. for the system.
config REGULATOR_TPS65023
tristate "TI TPS65023 Power regulators"
depends on I2C
help
This driver supports TPS65023 voltage regulator chips. TPS65023 provides
three step-down converters and two general-purpose LDO voltage regulators.
It supports TI's software based Class-2 SmartReflex implementation.
config REGULATOR_TPS6507X
tristate "TI TPS6507X Power regulators"
depends on I2C
help
This driver supports TPS6507X voltage regulator chips. TPS6507X provides
three step-down converters and two general-purpose LDO voltage regulators.
It supports TI's software based Class-2 SmartReflex implementation.
endif endif
...@@ -23,4 +23,7 @@ obj-$(CONFIG_REGULATOR_PCAP) += pcap-regulator.o ...@@ -23,4 +23,7 @@ obj-$(CONFIG_REGULATOR_PCAP) += pcap-regulator.o
obj-$(CONFIG_REGULATOR_MC13783) += mc13783.o obj-$(CONFIG_REGULATOR_MC13783) += mc13783.o
obj-$(CONFIG_REGULATOR_AB3100) += ab3100.o obj-$(CONFIG_REGULATOR_AB3100) += ab3100.o
obj-$(CONFIG_REGULATOR_TPS65023) += tps65023-regulator.o
obj-$(CONFIG_REGULATOR_TPS6507X) += tps6507x-regulator.o
ccflags-$(CONFIG_REGULATOR_DEBUG) += -DDEBUG ccflags-$(CONFIG_REGULATOR_DEBUG) += -DDEBUG
...@@ -37,7 +37,7 @@ static int has_full_constraints; ...@@ -37,7 +37,7 @@ static int has_full_constraints;
*/ */
struct regulator_map { struct regulator_map {
struct list_head list; struct list_head list;
struct device *dev; const char *dev_name; /* The dev_name() for the consumer */
const char *supply; const char *supply;
struct regulator_dev *regulator; struct regulator_dev *regulator;
}; };
...@@ -232,7 +232,7 @@ static ssize_t regulator_name_show(struct device *dev, ...@@ -232,7 +232,7 @@ static ssize_t regulator_name_show(struct device *dev,
struct regulator_dev *rdev = dev_get_drvdata(dev); struct regulator_dev *rdev = dev_get_drvdata(dev);
const char *name; const char *name;
if (rdev->constraints->name) if (rdev->constraints && rdev->constraints->name)
name = rdev->constraints->name; name = rdev->constraints->name;
else if (rdev->desc->name) else if (rdev->desc->name)
name = rdev->desc->name; name = rdev->desc->name;
...@@ -280,8 +280,13 @@ static ssize_t regulator_state_show(struct device *dev, ...@@ -280,8 +280,13 @@ static ssize_t regulator_state_show(struct device *dev,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
{ {
struct regulator_dev *rdev = dev_get_drvdata(dev); struct regulator_dev *rdev = dev_get_drvdata(dev);
ssize_t ret;
mutex_lock(&rdev->mutex);
ret = regulator_print_state(buf, _regulator_is_enabled(rdev));
mutex_unlock(&rdev->mutex);
return regulator_print_state(buf, _regulator_is_enabled(rdev)); return ret;
} }
static DEVICE_ATTR(state, 0444, regulator_state_show, NULL); static DEVICE_ATTR(state, 0444, regulator_state_show, NULL);
...@@ -857,23 +862,39 @@ static int set_supply(struct regulator_dev *rdev, ...@@ -857,23 +862,39 @@ static int set_supply(struct regulator_dev *rdev,
* set_consumer_device_supply: Bind a regulator to a symbolic supply * set_consumer_device_supply: Bind a regulator to a symbolic supply
* @rdev: regulator source * @rdev: regulator source
* @consumer_dev: device the supply applies to * @consumer_dev: device the supply applies to
* @consumer_dev_name: dev_name() string for device supply applies to
* @supply: symbolic name for supply * @supply: symbolic name for supply
* *
* Allows platform initialisation code to map physical regulator * Allows platform initialisation code to map physical regulator
* sources to symbolic names for supplies for use by devices. Devices * sources to symbolic names for supplies for use by devices. Devices
* should use these symbolic names to request regulators, avoiding the * should use these symbolic names to request regulators, avoiding the
* need to provide board-specific regulator names as platform data. * need to provide board-specific regulator names as platform data.
*
* Only one of consumer_dev and consumer_dev_name may be specified.
*/ */
static int set_consumer_device_supply(struct regulator_dev *rdev, static int set_consumer_device_supply(struct regulator_dev *rdev,
struct device *consumer_dev, const char *supply) struct device *consumer_dev, const char *consumer_dev_name,
const char *supply)
{ {
struct regulator_map *node; struct regulator_map *node;
int has_dev;
if (consumer_dev && consumer_dev_name)
return -EINVAL;
if (!consumer_dev_name && consumer_dev)
consumer_dev_name = dev_name(consumer_dev);
if (supply == NULL) if (supply == NULL)
return -EINVAL; return -EINVAL;
if (consumer_dev_name != NULL)
has_dev = 1;
else
has_dev = 0;
list_for_each_entry(node, &regulator_map_list, list) { list_for_each_entry(node, &regulator_map_list, list) {
if (consumer_dev != node->dev) if (consumer_dev_name != node->dev_name)
continue; continue;
if (strcmp(node->supply, supply) != 0) if (strcmp(node->supply, supply) != 0)
continue; continue;
...@@ -886,30 +907,45 @@ static int set_consumer_device_supply(struct regulator_dev *rdev, ...@@ -886,30 +907,45 @@ static int set_consumer_device_supply(struct regulator_dev *rdev,
return -EBUSY; return -EBUSY;
} }
node = kmalloc(sizeof(struct regulator_map), GFP_KERNEL); node = kzalloc(sizeof(struct regulator_map), GFP_KERNEL);
if (node == NULL) if (node == NULL)
return -ENOMEM; return -ENOMEM;
node->regulator = rdev; node->regulator = rdev;
node->dev = consumer_dev;
node->supply = supply; node->supply = supply;
if (has_dev) {
node->dev_name = kstrdup(consumer_dev_name, GFP_KERNEL);
if (node->dev_name == NULL) {
kfree(node);
return -ENOMEM;
}
}
list_add(&node->list, &regulator_map_list); list_add(&node->list, &regulator_map_list);
return 0; return 0;
} }
static void unset_consumer_device_supply(struct regulator_dev *rdev, static void unset_consumer_device_supply(struct regulator_dev *rdev,
struct device *consumer_dev) const char *consumer_dev_name, struct device *consumer_dev)
{ {
struct regulator_map *node, *n; struct regulator_map *node, *n;
if (consumer_dev && !consumer_dev_name)
consumer_dev_name = dev_name(consumer_dev);
list_for_each_entry_safe(node, n, &regulator_map_list, list) { list_for_each_entry_safe(node, n, &regulator_map_list, list) {
if (rdev == node->regulator && if (rdev != node->regulator)
consumer_dev == node->dev) { continue;
list_del(&node->list);
kfree(node); if (consumer_dev_name && node->dev_name &&
return; strcmp(consumer_dev_name, node->dev_name))
} continue;
list_del(&node->list);
kfree(node->dev_name);
kfree(node);
return;
} }
} }
...@@ -920,6 +956,7 @@ static void unset_regulator_supplies(struct regulator_dev *rdev) ...@@ -920,6 +956,7 @@ static void unset_regulator_supplies(struct regulator_dev *rdev)
list_for_each_entry_safe(node, n, &regulator_map_list, list) { list_for_each_entry_safe(node, n, &regulator_map_list, list) {
if (rdev == node->regulator) { if (rdev == node->regulator) {
list_del(&node->list); list_del(&node->list);
kfree(node->dev_name);
kfree(node); kfree(node);
return; return;
} }
...@@ -1001,35 +1038,33 @@ static struct regulator *create_regulator(struct regulator_dev *rdev, ...@@ -1001,35 +1038,33 @@ static struct regulator *create_regulator(struct regulator_dev *rdev,
return NULL; return NULL;
} }
/** /* Internal regulator request function */
* regulator_get - lookup and obtain a reference to a regulator. static struct regulator *_regulator_get(struct device *dev, const char *id,
* @dev: device for regulator "consumer" int exclusive)
* @id: Supply name or regulator ID.
*
* Returns a struct regulator corresponding to the regulator producer,
* or IS_ERR() condition containing errno.
*
* Use of supply names configured via regulator_set_device_supply() is
* strongly encouraged. It is recommended that the supply name used
* should match the name used for the supply and/or the relevant
* device pins in the datasheet.
*/
struct regulator *regulator_get(struct device *dev, const char *id)
{ {
struct regulator_dev *rdev; struct regulator_dev *rdev;
struct regulator_map *map; struct regulator_map *map;
struct regulator *regulator = ERR_PTR(-ENODEV); struct regulator *regulator = ERR_PTR(-ENODEV);
const char *devname = NULL;
int ret;
if (id == NULL) { if (id == NULL) {
printk(KERN_ERR "regulator: get() with no identifier\n"); printk(KERN_ERR "regulator: get() with no identifier\n");
return regulator; return regulator;
} }
if (dev)
devname = dev_name(dev);
mutex_lock(&regulator_list_mutex); mutex_lock(&regulator_list_mutex);
list_for_each_entry(map, &regulator_map_list, list) { list_for_each_entry(map, &regulator_map_list, list) {
if (dev == map->dev && /* If the mapping has a device set up it must match */
strcmp(map->supply, id) == 0) { if (map->dev_name &&
(!devname || strcmp(map->dev_name, devname)))
continue;
if (strcmp(map->supply, id) == 0) {
rdev = map->regulator; rdev = map->regulator;
goto found; goto found;
} }
...@@ -1038,6 +1073,16 @@ struct regulator *regulator_get(struct device *dev, const char *id) ...@@ -1038,6 +1073,16 @@ struct regulator *regulator_get(struct device *dev, const char *id)
return regulator; return regulator;
found: found:
if (rdev->exclusive) {
regulator = ERR_PTR(-EPERM);
goto out;
}
if (exclusive && rdev->open_count) {
regulator = ERR_PTR(-EBUSY);
goto out;
}
if (!try_module_get(rdev->owner)) if (!try_module_get(rdev->owner))
goto out; goto out;
...@@ -1047,12 +1092,69 @@ struct regulator *regulator_get(struct device *dev, const char *id) ...@@ -1047,12 +1092,69 @@ struct regulator *regulator_get(struct device *dev, const char *id)
module_put(rdev->owner); module_put(rdev->owner);
} }
rdev->open_count++;
if (exclusive) {
rdev->exclusive = 1;
ret = _regulator_is_enabled(rdev);
if (ret > 0)
rdev->use_count = 1;
else
rdev->use_count = 0;
}
out: out:
mutex_unlock(&regulator_list_mutex); mutex_unlock(&regulator_list_mutex);
return regulator; return regulator;
} }
/**
* regulator_get - lookup and obtain a reference to a regulator.
* @dev: device for regulator "consumer"
* @id: Supply name or regulator ID.
*
* Returns a struct regulator corresponding to the regulator producer,
* or IS_ERR() condition containing errno.
*
* Use of supply names configured via regulator_set_device_supply() is
* strongly encouraged. It is recommended that the supply name used
* should match the name used for the supply and/or the relevant
* device pins in the datasheet.
*/
struct regulator *regulator_get(struct device *dev, const char *id)
{
return _regulator_get(dev, id, 0);
}
EXPORT_SYMBOL_GPL(regulator_get); EXPORT_SYMBOL_GPL(regulator_get);
/**
* regulator_get_exclusive - obtain exclusive access to a regulator.
* @dev: device for regulator "consumer"
* @id: Supply name or regulator ID.
*
* Returns a struct regulator corresponding to the regulator producer,
* or IS_ERR() condition containing errno. Other consumers will be
* unable to obtain this reference is held and the use count for the
* regulator will be initialised to reflect the current state of the
* regulator.
*
* This is intended for use by consumers which cannot tolerate shared
* use of the regulator such as those which need to force the
* regulator off for correct operation of the hardware they are
* controlling.
*
* Use of supply names configured via regulator_set_device_supply() is
* strongly encouraged. It is recommended that the supply name used
* should match the name used for the supply and/or the relevant
* device pins in the datasheet.
*/
struct regulator *regulator_get_exclusive(struct device *dev, const char *id)
{
return _regulator_get(dev, id, 1);
}
EXPORT_SYMBOL_GPL(regulator_get_exclusive);
/** /**
* regulator_put - "free" the regulator source * regulator_put - "free" the regulator source
* @regulator: regulator source * @regulator: regulator source
...@@ -1081,21 +1183,29 @@ void regulator_put(struct regulator *regulator) ...@@ -1081,21 +1183,29 @@ void regulator_put(struct regulator *regulator)
list_del(&regulator->list); list_del(&regulator->list);
kfree(regulator); kfree(regulator);
rdev->open_count--;
rdev->exclusive = 0;
module_put(rdev->owner); module_put(rdev->owner);
mutex_unlock(&regulator_list_mutex); mutex_unlock(&regulator_list_mutex);
} }
EXPORT_SYMBOL_GPL(regulator_put); EXPORT_SYMBOL_GPL(regulator_put);
static int _regulator_can_change_status(struct regulator_dev *rdev)
{
if (!rdev->constraints)
return 0;
if (rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_STATUS)
return 1;
else
return 0;
}
/* locks held by regulator_enable() */ /* locks held by regulator_enable() */
static int _regulator_enable(struct regulator_dev *rdev) static int _regulator_enable(struct regulator_dev *rdev)
{ {
int ret = -EINVAL; int ret;
if (!rdev->constraints) {
printk(KERN_ERR "%s: %s has no constraints\n",
__func__, rdev->desc->name);
return ret;
}
/* do we need to enable the supply regulator first */ /* do we need to enable the supply regulator first */
if (rdev->supply) { if (rdev->supply) {
...@@ -1108,24 +1218,35 @@ static int _regulator_enable(struct regulator_dev *rdev) ...@@ -1108,24 +1218,35 @@ static int _regulator_enable(struct regulator_dev *rdev)
} }
/* check voltage and requested load before enabling */ /* check voltage and requested load before enabling */
if (rdev->desc->ops->enable) { if (rdev->constraints &&
(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_DRMS))
if (rdev->constraints && drms_uA_update(rdev);
(rdev->constraints->valid_ops_mask &
REGULATOR_CHANGE_DRMS)) if (rdev->use_count == 0) {
drms_uA_update(rdev); /* The regulator may on if it's not switchable or left on */
ret = _regulator_is_enabled(rdev);
ret = rdev->desc->ops->enable(rdev); if (ret == -EINVAL || ret == 0) {
if (ret < 0) { if (!_regulator_can_change_status(rdev))
printk(KERN_ERR "%s: failed to enable %s: %d\n", return -EPERM;
if (rdev->desc->ops->enable) {
ret = rdev->desc->ops->enable(rdev);
if (ret < 0)
return ret;
} else {
return -EINVAL;
}
} else if (ret < 0) {
printk(KERN_ERR "%s: is_enabled() failed for %s: %d\n",
__func__, rdev->desc->name, ret); __func__, rdev->desc->name, ret);
return ret; return ret;
} }
rdev->use_count++; /* Fallthrough on positive return values - already enabled */
return ret;
} }
return ret; rdev->use_count++;
return 0;
} }
/** /**
...@@ -1165,7 +1286,8 @@ static int _regulator_disable(struct regulator_dev *rdev) ...@@ -1165,7 +1286,8 @@ static int _regulator_disable(struct regulator_dev *rdev)
if (rdev->use_count == 1 && !rdev->constraints->always_on) { if (rdev->use_count == 1 && !rdev->constraints->always_on) {
/* we are last user */ /* we are last user */
if (rdev->desc->ops->disable) { if (_regulator_can_change_status(rdev) &&
rdev->desc->ops->disable) {
ret = rdev->desc->ops->disable(rdev); ret = rdev->desc->ops->disable(rdev);
if (ret < 0) { if (ret < 0) {
printk(KERN_ERR "%s: failed to disable %s\n", printk(KERN_ERR "%s: failed to disable %s\n",
...@@ -1265,20 +1387,11 @@ EXPORT_SYMBOL_GPL(regulator_force_disable); ...@@ -1265,20 +1387,11 @@ EXPORT_SYMBOL_GPL(regulator_force_disable);
static int _regulator_is_enabled(struct regulator_dev *rdev) static int _regulator_is_enabled(struct regulator_dev *rdev)
{ {
int ret;
mutex_lock(&rdev->mutex);
/* sanity check */ /* sanity check */
if (!rdev->desc->ops->is_enabled) { if (!rdev->desc->ops->is_enabled)
ret = -EINVAL; return -EINVAL;
goto out;
}
ret = rdev->desc->ops->is_enabled(rdev); return rdev->desc->ops->is_enabled(rdev);
out:
mutex_unlock(&rdev->mutex);
return ret;
} }
/** /**
...@@ -1295,7 +1408,13 @@ static int _regulator_is_enabled(struct regulator_dev *rdev) ...@@ -1295,7 +1408,13 @@ static int _regulator_is_enabled(struct regulator_dev *rdev)
*/ */
int regulator_is_enabled(struct regulator *regulator) int regulator_is_enabled(struct regulator *regulator)
{ {
return _regulator_is_enabled(regulator->rdev); int ret;
mutex_lock(&regulator->rdev->mutex);
ret = _regulator_is_enabled(regulator->rdev);
mutex_unlock(&regulator->rdev->mutex);
return ret;
} }
EXPORT_SYMBOL_GPL(regulator_is_enabled); EXPORT_SYMBOL_GPL(regulator_is_enabled);
...@@ -1349,6 +1468,35 @@ int regulator_list_voltage(struct regulator *regulator, unsigned selector) ...@@ -1349,6 +1468,35 @@ int regulator_list_voltage(struct regulator *regulator, unsigned selector)
} }
EXPORT_SYMBOL_GPL(regulator_list_voltage); EXPORT_SYMBOL_GPL(regulator_list_voltage);
/**
* regulator_is_supported_voltage - check if a voltage range can be supported
*
* @regulator: Regulator to check.
* @min_uV: Minimum required voltage in uV.
* @max_uV: Maximum required voltage in uV.
*
* Returns a boolean or a negative error code.
*/
int regulator_is_supported_voltage(struct regulator *regulator,
int min_uV, int max_uV)
{
int i, voltages, ret;
ret = regulator_count_voltages(regulator);
if (ret < 0)
return ret;
voltages = ret;
for (i = 0; i < voltages; i++) {
ret = regulator_list_voltage(regulator, i);
if (ret >= min_uV && ret <= max_uV)
return 1;
}
return 0;
}
/** /**
* regulator_set_voltage - set regulator output voltage * regulator_set_voltage - set regulator output voltage
* @regulator: regulator source * @regulator: regulator source
...@@ -2091,11 +2239,13 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc, ...@@ -2091,11 +2239,13 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc,
for (i = 0; i < init_data->num_consumer_supplies; i++) { for (i = 0; i < init_data->num_consumer_supplies; i++) {
ret = set_consumer_device_supply(rdev, ret = set_consumer_device_supply(rdev,
init_data->consumer_supplies[i].dev, init_data->consumer_supplies[i].dev,
init_data->consumer_supplies[i].dev_name,
init_data->consumer_supplies[i].supply); init_data->consumer_supplies[i].supply);
if (ret < 0) { if (ret < 0) {
for (--i; i >= 0; i--) for (--i; i >= 0; i--)
unset_consumer_device_supply(rdev, unset_consumer_device_supply(rdev,
init_data->consumer_supplies[i].dev); init_data->consumer_supplies[i].dev_name,
init_data->consumer_supplies[i].dev);
goto scrub; goto scrub;
} }
} }
...@@ -2130,6 +2280,7 @@ void regulator_unregister(struct regulator_dev *rdev) ...@@ -2130,6 +2280,7 @@ void regulator_unregister(struct regulator_dev *rdev)
return; return;
mutex_lock(&regulator_list_mutex); mutex_lock(&regulator_list_mutex);
WARN_ON(rdev->open_count);
unset_regulator_supplies(rdev); unset_regulator_supplies(rdev);
list_del(&rdev->list); list_del(&rdev->list);
if (rdev->supply) if (rdev->supply)
...@@ -2277,14 +2428,14 @@ static int __init regulator_init_complete(void) ...@@ -2277,14 +2428,14 @@ static int __init regulator_init_complete(void)
ops = rdev->desc->ops; ops = rdev->desc->ops;
c = rdev->constraints; c = rdev->constraints;
if (c->name) if (c && c->name)
name = c->name; name = c->name;
else if (rdev->desc->name) else if (rdev->desc->name)
name = rdev->desc->name; name = rdev->desc->name;
else else
name = "regulator"; name = "regulator";
if (!ops->disable || c->always_on) if (!ops->disable || (c && c->always_on))
continue; continue;
mutex_lock(&rdev->mutex); mutex_lock(&rdev->mutex);
......
...@@ -64,6 +64,14 @@ ...@@ -64,6 +64,14 @@
#define DA9034_MDTV2 (0x33) #define DA9034_MDTV2 (0x33)
#define DA9034_MVRC (0x34) #define DA9034_MVRC (0x34)
/* DA9035 Registers. DA9034 Registers are comptabile to DA9035. */
#define DA9035_OVER3 (0x12)
#define DA9035_VCC2 (0x1f)
#define DA9035_3DTV1 (0x2c)
#define DA9035_3DTV2 (0x2d)
#define DA9035_3VRC (0x2e)
#define DA9035_AUTOSKIP (0x2f)
struct da903x_regulator_info { struct da903x_regulator_info {
struct regulator_desc desc; struct regulator_desc desc;
...@@ -79,6 +87,10 @@ struct da903x_regulator_info { ...@@ -79,6 +87,10 @@ struct da903x_regulator_info {
int enable_bit; int enable_bit;
}; };
static int da9034_ldo12_data[] = { 1700, 1750, 1800, 1850, 1900, 1950,
2000, 2050, 2700, 2750, 2800, 2850,
2900, 2950, 3000, 3050 };
static inline struct device *to_da903x_dev(struct regulator_dev *rdev) static inline struct device *to_da903x_dev(struct regulator_dev *rdev)
{ {
return rdev_get_dev(rdev)->parent->parent; return rdev_get_dev(rdev)->parent->parent;
...@@ -162,6 +174,17 @@ static int da903x_is_enabled(struct regulator_dev *rdev) ...@@ -162,6 +174,17 @@ static int da903x_is_enabled(struct regulator_dev *rdev)
return !!(reg_val & (1 << info->enable_bit)); return !!(reg_val & (1 << info->enable_bit));
} }
static int da903x_list_voltage(struct regulator_dev *rdev, unsigned selector)
{
struct da903x_regulator_info *info = rdev_get_drvdata(rdev);
int ret;
ret = info->min_uV + info->step_uV * selector;
if (ret > info->max_uV)
return -EINVAL;
return ret;
}
/* DA9030 specific operations */ /* DA9030 specific operations */
static int da9030_set_ldo1_15_voltage(struct regulator_dev *rdev, static int da9030_set_ldo1_15_voltage(struct regulator_dev *rdev,
int min_uV, int max_uV) int min_uV, int max_uV)
...@@ -278,7 +301,7 @@ static int da9034_set_ldo12_voltage(struct regulator_dev *rdev, ...@@ -278,7 +301,7 @@ static int da9034_set_ldo12_voltage(struct regulator_dev *rdev,
} }
val = (min_uV - info->min_uV + info->step_uV - 1) / info->step_uV; val = (min_uV - info->min_uV + info->step_uV - 1) / info->step_uV;
val = (val > 7 || val < 20) ? 8 : val - 12; val = (val >= 20) ? val - 12 : ((val > 7) ? 8 : val);
val <<= info->vol_shift; val <<= info->vol_shift;
mask = ((1 << info->vol_nbits) - 1) << info->vol_shift; mask = ((1 << info->vol_nbits) - 1) << info->vol_shift;
...@@ -305,9 +328,18 @@ static int da9034_get_ldo12_voltage(struct regulator_dev *rdev) ...@@ -305,9 +328,18 @@ static int da9034_get_ldo12_voltage(struct regulator_dev *rdev)
return info->min_uV + info->step_uV * val; return info->min_uV + info->step_uV * val;
} }
static int da9034_list_ldo12_voltage(struct regulator_dev *rdev,
unsigned selector)
{
if (selector > ARRAY_SIZE(da9034_ldo12_data))
return -EINVAL;
return da9034_ldo12_data[selector] * 1000;
}
static struct regulator_ops da903x_regulator_ldo_ops = { static struct regulator_ops da903x_regulator_ldo_ops = {
.set_voltage = da903x_set_ldo_voltage, .set_voltage = da903x_set_ldo_voltage,
.get_voltage = da903x_get_voltage, .get_voltage = da903x_get_voltage,
.list_voltage = da903x_list_voltage,
.enable = da903x_enable, .enable = da903x_enable,
.disable = da903x_disable, .disable = da903x_disable,
.is_enabled = da903x_is_enabled, .is_enabled = da903x_is_enabled,
...@@ -317,6 +349,7 @@ static struct regulator_ops da903x_regulator_ldo_ops = { ...@@ -317,6 +349,7 @@ static struct regulator_ops da903x_regulator_ldo_ops = {
static struct regulator_ops da9030_regulator_ldo14_ops = { static struct regulator_ops da9030_regulator_ldo14_ops = {
.set_voltage = da9030_set_ldo14_voltage, .set_voltage = da9030_set_ldo14_voltage,
.get_voltage = da9030_get_ldo14_voltage, .get_voltage = da9030_get_ldo14_voltage,
.list_voltage = da903x_list_voltage,
.enable = da903x_enable, .enable = da903x_enable,
.disable = da903x_disable, .disable = da903x_disable,
.is_enabled = da903x_is_enabled, .is_enabled = da903x_is_enabled,
...@@ -326,6 +359,7 @@ static struct regulator_ops da9030_regulator_ldo14_ops = { ...@@ -326,6 +359,7 @@ static struct regulator_ops da9030_regulator_ldo14_ops = {
static struct regulator_ops da9030_regulator_ldo1_15_ops = { static struct regulator_ops da9030_regulator_ldo1_15_ops = {
.set_voltage = da9030_set_ldo1_15_voltage, .set_voltage = da9030_set_ldo1_15_voltage,
.get_voltage = da903x_get_voltage, .get_voltage = da903x_get_voltage,
.list_voltage = da903x_list_voltage,
.enable = da903x_enable, .enable = da903x_enable,
.disable = da903x_disable, .disable = da903x_disable,
.is_enabled = da903x_is_enabled, .is_enabled = da903x_is_enabled,
...@@ -334,6 +368,7 @@ static struct regulator_ops da9030_regulator_ldo1_15_ops = { ...@@ -334,6 +368,7 @@ static struct regulator_ops da9030_regulator_ldo1_15_ops = {
static struct regulator_ops da9034_regulator_dvc_ops = { static struct regulator_ops da9034_regulator_dvc_ops = {
.set_voltage = da9034_set_dvc_voltage, .set_voltage = da9034_set_dvc_voltage,
.get_voltage = da903x_get_voltage, .get_voltage = da903x_get_voltage,
.list_voltage = da903x_list_voltage,
.enable = da903x_enable, .enable = da903x_enable,
.disable = da903x_disable, .disable = da903x_disable,
.is_enabled = da903x_is_enabled, .is_enabled = da903x_is_enabled,
...@@ -343,6 +378,7 @@ static struct regulator_ops da9034_regulator_dvc_ops = { ...@@ -343,6 +378,7 @@ static struct regulator_ops da9034_regulator_dvc_ops = {
static struct regulator_ops da9034_regulator_ldo12_ops = { static struct regulator_ops da9034_regulator_ldo12_ops = {
.set_voltage = da9034_set_ldo12_voltage, .set_voltage = da9034_set_ldo12_voltage,
.get_voltage = da9034_get_ldo12_voltage, .get_voltage = da9034_get_ldo12_voltage,
.list_voltage = da9034_list_ldo12_voltage,
.enable = da903x_enable, .enable = da903x_enable,
.disable = da903x_disable, .disable = da903x_disable,
.is_enabled = da903x_is_enabled, .is_enabled = da903x_is_enabled,
...@@ -355,6 +391,7 @@ static struct regulator_ops da9034_regulator_ldo12_ops = { ...@@ -355,6 +391,7 @@ static struct regulator_ops da9034_regulator_ldo12_ops = {
.ops = &da903x_regulator_ldo_ops, \ .ops = &da903x_regulator_ldo_ops, \
.type = REGULATOR_VOLTAGE, \ .type = REGULATOR_VOLTAGE, \
.id = _pmic##_ID_LDO##_id, \ .id = _pmic##_ID_LDO##_id, \
.n_voltages = (step) ? ((max - min) / step + 1) : 1, \
.owner = THIS_MODULE, \ .owner = THIS_MODULE, \
}, \ }, \
.min_uV = (min) * 1000, \ .min_uV = (min) * 1000, \
...@@ -367,24 +404,25 @@ static struct regulator_ops da9034_regulator_ldo12_ops = { ...@@ -367,24 +404,25 @@ static struct regulator_ops da9034_regulator_ldo12_ops = {
.enable_bit = (ebit), \ .enable_bit = (ebit), \
} }
#define DA9034_DVC(_id, min, max, step, vreg, nbits, ureg, ubit, ereg, ebit) \ #define DA903x_DVC(_pmic, _id, min, max, step, vreg, nbits, ureg, ubit, ereg, ebit) \
{ \ { \
.desc = { \ .desc = { \
.name = #_id, \ .name = #_id, \
.ops = &da9034_regulator_dvc_ops, \ .ops = &da9034_regulator_dvc_ops, \
.type = REGULATOR_VOLTAGE, \ .type = REGULATOR_VOLTAGE, \
.id = DA9034_ID_##_id, \ .id = _pmic##_ID_##_id, \
.n_voltages = (step) ? ((max - min) / step + 1) : 1, \
.owner = THIS_MODULE, \ .owner = THIS_MODULE, \
}, \ }, \
.min_uV = (min) * 1000, \ .min_uV = (min) * 1000, \
.max_uV = (max) * 1000, \ .max_uV = (max) * 1000, \
.step_uV = (step) * 1000, \ .step_uV = (step) * 1000, \
.vol_reg = DA9034_##vreg, \ .vol_reg = _pmic##_##vreg, \
.vol_shift = (0), \ .vol_shift = (0), \
.vol_nbits = (nbits), \ .vol_nbits = (nbits), \
.update_reg = DA9034_##ureg, \ .update_reg = _pmic##_##ureg, \
.update_bit = (ubit), \ .update_bit = (ubit), \
.enable_reg = DA9034_##ereg, \ .enable_reg = _pmic##_##ereg, \
.enable_bit = (ebit), \ .enable_bit = (ebit), \
} }
...@@ -394,8 +432,22 @@ static struct regulator_ops da9034_regulator_ldo12_ops = { ...@@ -394,8 +432,22 @@ static struct regulator_ops da9034_regulator_ldo12_ops = {
#define DA9030_LDO(_id, min, max, step, vreg, shift, nbits, ereg, ebit) \ #define DA9030_LDO(_id, min, max, step, vreg, shift, nbits, ereg, ebit) \
DA903x_LDO(DA9030, _id, min, max, step, vreg, shift, nbits, ereg, ebit) DA903x_LDO(DA9030, _id, min, max, step, vreg, shift, nbits, ereg, ebit)
#define DA9030_DVC(_id, min, max, step, vreg, nbits, ureg, ubit, ereg, ebit) \
DA903x_DVC(DA9030, _id, min, max, step, vreg, nbits, ureg, ubit, \
ereg, ebit)
#define DA9034_DVC(_id, min, max, step, vreg, nbits, ureg, ubit, ereg, ebit) \
DA903x_DVC(DA9034, _id, min, max, step, vreg, nbits, ureg, ubit, \
ereg, ebit)
#define DA9035_DVC(_id, min, max, step, vreg, nbits, ureg, ubit, ereg, ebit) \
DA903x_DVC(DA9035, _id, min, max, step, vreg, nbits, ureg, ubit, \
ereg, ebit)
static struct da903x_regulator_info da903x_regulator_info[] = { static struct da903x_regulator_info da903x_regulator_info[] = {
/* DA9030 */ /* DA9030 */
DA9030_DVC(BUCK2, 850, 1625, 25, BUCK2DVM1, 5, BUCK2DVM1, 7, RCTL11, 0),
DA9030_LDO( 1, 1200, 3200, 100, LDO1, 0, 5, RCTL12, 1), DA9030_LDO( 1, 1200, 3200, 100, LDO1, 0, 5, RCTL12, 1),
DA9030_LDO( 2, 1800, 3200, 100, LDO23, 0, 4, RCTL12, 2), DA9030_LDO( 2, 1800, 3200, 100, LDO23, 0, 4, RCTL12, 2),
DA9030_LDO( 3, 1800, 3200, 100, LDO23, 4, 4, RCTL12, 3), DA9030_LDO( 3, 1800, 3200, 100, LDO23, 4, 4, RCTL12, 3),
...@@ -417,9 +469,9 @@ static struct da903x_regulator_info da903x_regulator_info[] = { ...@@ -417,9 +469,9 @@ static struct da903x_regulator_info da903x_regulator_info[] = {
DA9030_LDO(13, 2100, 2100, 0, INVAL, 0, 0, RCTL11, 3), /* fixed @2.1V */ DA9030_LDO(13, 2100, 2100, 0, INVAL, 0, 0, RCTL11, 3), /* fixed @2.1V */
/* DA9034 */ /* DA9034 */
DA9034_DVC(BUCK1, 725, 1500, 25, ADTV1, 5, VCC1, 0, OVER1, 0), DA9034_DVC(BUCK1, 725, 1500, 25, ADTV2, 5, VCC1, 0, OVER1, 0),
DA9034_DVC(BUCK2, 725, 1500, 25, CDTV1, 5, VCC1, 2, OVER1, 1), DA9034_DVC(BUCK2, 725, 1500, 25, CDTV2, 5, VCC1, 2, OVER1, 1),
DA9034_DVC(LDO2, 725, 1500, 25, SDTV1, 5, VCC1, 4, OVER1, 2), DA9034_DVC(LDO2, 725, 1500, 25, SDTV2, 5, VCC1, 4, OVER1, 2),
DA9034_DVC(LDO1, 1700, 2075, 25, MDTV1, 4, VCC1, 6, OVER3, 4), DA9034_DVC(LDO1, 1700, 2075, 25, MDTV1, 4, VCC1, 6, OVER3, 4),
DA9034_LDO( 3, 1800, 3300, 100, LDO643, 0, 4, OVER3, 5), DA9034_LDO( 3, 1800, 3300, 100, LDO643, 0, 4, OVER3, 5),
...@@ -435,6 +487,9 @@ static struct da903x_regulator_info da903x_regulator_info[] = { ...@@ -435,6 +487,9 @@ static struct da903x_regulator_info da903x_regulator_info[] = {
DA9034_LDO(14, 1800, 3300, 100, LDO1514, 0, 4, OVER3, 0), DA9034_LDO(14, 1800, 3300, 100, LDO1514, 0, 4, OVER3, 0),
DA9034_LDO(15, 1800, 3300, 100, LDO1514, 4, 4, OVER3, 1), DA9034_LDO(15, 1800, 3300, 100, LDO1514, 4, 4, OVER3, 1),
DA9034_LDO(5, 3100, 3100, 0, INVAL, 0, 0, OVER3, 7), /* fixed @3.1V */ DA9034_LDO(5, 3100, 3100, 0, INVAL, 0, 0, OVER3, 7), /* fixed @3.1V */
/* DA9035 */
DA9035_DVC(BUCK3, 1800, 2200, 100, 3DTV1, 3, VCC2, 0, OVER3, 3),
}; };
static inline struct da903x_regulator_info *find_regulator_info(int id) static inline struct da903x_regulator_info *find_regulator_info(int id)
...@@ -462,8 +517,10 @@ static int __devinit da903x_regulator_probe(struct platform_device *pdev) ...@@ -462,8 +517,10 @@ static int __devinit da903x_regulator_probe(struct platform_device *pdev)
} }
/* Workaround for the weird LDO12 voltage setting */ /* Workaround for the weird LDO12 voltage setting */
if (ri->desc.id == DA9034_ID_LDO12) if (ri->desc.id == DA9034_ID_LDO12) {
ri->desc.ops = &da9034_regulator_ldo12_ops; ri->desc.ops = &da9034_regulator_ldo12_ops;
ri->desc.n_voltages = ARRAY_SIZE(da9034_ldo12_data);
}
if (ri->desc.id == DA9030_ID_LDO14) if (ri->desc.id == DA9030_ID_LDO14)
ri->desc.ops = &da9030_regulator_ldo14_ops; ri->desc.ops = &da9030_regulator_ldo14_ops;
......
...@@ -5,6 +5,9 @@ ...@@ -5,6 +5,9 @@
* *
* Author: Mark Brown <broonie@opensource.wolfsonmicro.com> * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
* *
* Copyright (c) 2009 Nokia Corporation
* Roger Quadros <ext-roger.quadros@nokia.com>
*
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as * modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the * published by the Free Software Foundation; either version 2 of the
...@@ -20,20 +23,45 @@ ...@@ -20,20 +23,45 @@
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/regulator/driver.h> #include <linux/regulator/driver.h>
#include <linux/regulator/fixed.h> #include <linux/regulator/fixed.h>
#include <linux/gpio.h>
struct fixed_voltage_data { struct fixed_voltage_data {
struct regulator_desc desc; struct regulator_desc desc;
struct regulator_dev *dev; struct regulator_dev *dev;
int microvolts; int microvolts;
int gpio;
unsigned enable_high:1;
unsigned is_enabled:1;
}; };
static int fixed_voltage_is_enabled(struct regulator_dev *dev) static int fixed_voltage_is_enabled(struct regulator_dev *dev)
{ {
return 1; struct fixed_voltage_data *data = rdev_get_drvdata(dev);
return data->is_enabled;
} }
static int fixed_voltage_enable(struct regulator_dev *dev) static int fixed_voltage_enable(struct regulator_dev *dev)
{ {
struct fixed_voltage_data *data = rdev_get_drvdata(dev);
if (gpio_is_valid(data->gpio)) {
gpio_set_value_cansleep(data->gpio, data->enable_high);
data->is_enabled = 1;
}
return 0;
}
static int fixed_voltage_disable(struct regulator_dev *dev)
{
struct fixed_voltage_data *data = rdev_get_drvdata(dev);
if (gpio_is_valid(data->gpio)) {
gpio_set_value_cansleep(data->gpio, !data->enable_high);
data->is_enabled = 0;
}
return 0; return 0;
} }
...@@ -58,6 +86,7 @@ static int fixed_voltage_list_voltage(struct regulator_dev *dev, ...@@ -58,6 +86,7 @@ static int fixed_voltage_list_voltage(struct regulator_dev *dev,
static struct regulator_ops fixed_voltage_ops = { static struct regulator_ops fixed_voltage_ops = {
.is_enabled = fixed_voltage_is_enabled, .is_enabled = fixed_voltage_is_enabled,
.enable = fixed_voltage_enable, .enable = fixed_voltage_enable,
.disable = fixed_voltage_disable,
.get_voltage = fixed_voltage_get_voltage, .get_voltage = fixed_voltage_get_voltage,
.list_voltage = fixed_voltage_list_voltage, .list_voltage = fixed_voltage_list_voltage,
}; };
...@@ -70,12 +99,14 @@ static int regulator_fixed_voltage_probe(struct platform_device *pdev) ...@@ -70,12 +99,14 @@ static int regulator_fixed_voltage_probe(struct platform_device *pdev)
drvdata = kzalloc(sizeof(struct fixed_voltage_data), GFP_KERNEL); drvdata = kzalloc(sizeof(struct fixed_voltage_data), GFP_KERNEL);
if (drvdata == NULL) { if (drvdata == NULL) {
dev_err(&pdev->dev, "Failed to allocate device data\n");
ret = -ENOMEM; ret = -ENOMEM;
goto err; goto err;
} }
drvdata->desc.name = kstrdup(config->supply_name, GFP_KERNEL); drvdata->desc.name = kstrdup(config->supply_name, GFP_KERNEL);
if (drvdata->desc.name == NULL) { if (drvdata->desc.name == NULL) {
dev_err(&pdev->dev, "Failed to allocate supply name\n");
ret = -ENOMEM; ret = -ENOMEM;
goto err; goto err;
} }
...@@ -85,12 +116,62 @@ static int regulator_fixed_voltage_probe(struct platform_device *pdev) ...@@ -85,12 +116,62 @@ static int regulator_fixed_voltage_probe(struct platform_device *pdev)
drvdata->desc.n_voltages = 1; drvdata->desc.n_voltages = 1;
drvdata->microvolts = config->microvolts; drvdata->microvolts = config->microvolts;
drvdata->gpio = config->gpio;
if (gpio_is_valid(config->gpio)) {
drvdata->enable_high = config->enable_high;
/* FIXME: Remove below print warning
*
* config->gpio must be set to -EINVAL by platform code if
* GPIO control is not required. However, early adopters
* not requiring GPIO control may forget to initialize
* config->gpio to -EINVAL. This will cause GPIO 0 to be used
* for GPIO control.
*
* This warning will be removed once there are a couple of users
* for this driver.
*/
if (!config->gpio)
dev_warn(&pdev->dev,
"using GPIO 0 for regulator enable control\n");
ret = gpio_request(config->gpio, config->supply_name);
if (ret) {
dev_err(&pdev->dev,
"Could not obtain regulator enable GPIO %d: %d\n",
config->gpio, ret);
goto err_name;
}
/* set output direction without changing state
* to prevent glitch
*/
drvdata->is_enabled = config->enabled_at_boot;
ret = drvdata->is_enabled ?
config->enable_high : !config->enable_high;
ret = gpio_direction_output(config->gpio, ret);
if (ret) {
dev_err(&pdev->dev,
"Could not configure regulator enable GPIO %d direction: %d\n",
config->gpio, ret);
goto err_gpio;
}
} else {
/* Regulator without GPIO control is considered
* always enabled
*/
drvdata->is_enabled = 1;
}
drvdata->dev = regulator_register(&drvdata->desc, &pdev->dev, drvdata->dev = regulator_register(&drvdata->desc, &pdev->dev,
config->init_data, drvdata); config->init_data, drvdata);
if (IS_ERR(drvdata->dev)) { if (IS_ERR(drvdata->dev)) {
ret = PTR_ERR(drvdata->dev); ret = PTR_ERR(drvdata->dev);
goto err_name; dev_err(&pdev->dev, "Failed to register regulator: %d\n", ret);
goto err_gpio;
} }
platform_set_drvdata(pdev, drvdata); platform_set_drvdata(pdev, drvdata);
...@@ -100,6 +181,9 @@ static int regulator_fixed_voltage_probe(struct platform_device *pdev) ...@@ -100,6 +181,9 @@ static int regulator_fixed_voltage_probe(struct platform_device *pdev)
return 0; return 0;
err_gpio:
if (gpio_is_valid(config->gpio))
gpio_free(config->gpio);
err_name: err_name:
kfree(drvdata->desc.name); kfree(drvdata->desc.name);
err: err:
...@@ -115,6 +199,9 @@ static int regulator_fixed_voltage_remove(struct platform_device *pdev) ...@@ -115,6 +199,9 @@ static int regulator_fixed_voltage_remove(struct platform_device *pdev)
kfree(drvdata->desc.name); kfree(drvdata->desc.name);
kfree(drvdata); kfree(drvdata);
if (gpio_is_valid(drvdata->gpio))
gpio_free(drvdata->gpio);
return 0; return 0;
} }
......
...@@ -541,7 +541,7 @@ static struct i2c_driver lp3971_i2c_driver = { ...@@ -541,7 +541,7 @@ static struct i2c_driver lp3971_i2c_driver = {
static int __init lp3971_module_init(void) static int __init lp3971_module_init(void)
{ {
int ret = -ENODEV; int ret;
ret = i2c_add_driver(&lp3971_i2c_driver); ret = i2c_add_driver(&lp3971_i2c_driver);
if (ret != 0) if (ret != 0)
......
...@@ -24,11 +24,12 @@ ...@@ -24,11 +24,12 @@
#include <linux/mfd/pcf50633/core.h> #include <linux/mfd/pcf50633/core.h>
#include <linux/mfd/pcf50633/pmic.h> #include <linux/mfd/pcf50633/pmic.h>
#define PCF50633_REGULATOR(_name, _id) \ #define PCF50633_REGULATOR(_name, _id, _n) \
{ \ { \
.name = _name, \ .name = _name, \
.id = _id, \ .id = _id, \
.ops = &pcf50633_regulator_ops, \ .ops = &pcf50633_regulator_ops, \
.n_voltages = _n, \
.type = REGULATOR_VOLTAGE, \ .type = REGULATOR_VOLTAGE, \
.owner = THIS_MODULE, \ .owner = THIS_MODULE, \
} }
...@@ -149,33 +150,20 @@ static int pcf50633_regulator_set_voltage(struct regulator_dev *rdev, ...@@ -149,33 +150,20 @@ static int pcf50633_regulator_set_voltage(struct regulator_dev *rdev,
return pcf50633_reg_write(pcf, regnr, volt_bits); return pcf50633_reg_write(pcf, regnr, volt_bits);
} }
static int pcf50633_regulator_get_voltage(struct regulator_dev *rdev) static int pcf50633_regulator_voltage_value(enum pcf50633_regulator_id id,
u8 bits)
{ {
struct pcf50633 *pcf; int millivolts;
int regulator_id, millivolts, volt_bits;
u8 regnr;
pcf = rdev_get_drvdata(rdev);;
regulator_id = rdev_get_id(rdev); switch (id) {
if (regulator_id >= PCF50633_NUM_REGULATORS)
return -EINVAL;
regnr = pcf50633_regulator_registers[regulator_id];
volt_bits = pcf50633_reg_read(pcf, regnr);
if (volt_bits < 0)
return -1;
switch (regulator_id) {
case PCF50633_REGULATOR_AUTO: case PCF50633_REGULATOR_AUTO:
millivolts = auto_voltage_value(volt_bits); millivolts = auto_voltage_value(bits);
break; break;
case PCF50633_REGULATOR_DOWN1: case PCF50633_REGULATOR_DOWN1:
millivolts = down_voltage_value(volt_bits); millivolts = down_voltage_value(bits);
break; break;
case PCF50633_REGULATOR_DOWN2: case PCF50633_REGULATOR_DOWN2:
millivolts = down_voltage_value(volt_bits); millivolts = down_voltage_value(bits);
break; break;
case PCF50633_REGULATOR_LDO1: case PCF50633_REGULATOR_LDO1:
case PCF50633_REGULATOR_LDO2: case PCF50633_REGULATOR_LDO2:
...@@ -184,7 +172,7 @@ static int pcf50633_regulator_get_voltage(struct regulator_dev *rdev) ...@@ -184,7 +172,7 @@ static int pcf50633_regulator_get_voltage(struct regulator_dev *rdev)
case PCF50633_REGULATOR_LDO5: case PCF50633_REGULATOR_LDO5:
case PCF50633_REGULATOR_LDO6: case PCF50633_REGULATOR_LDO6:
case PCF50633_REGULATOR_HCLDO: case PCF50633_REGULATOR_HCLDO:
millivolts = ldo_voltage_value(volt_bits); millivolts = ldo_voltage_value(bits);
break; break;
default: default:
return -EINVAL; return -EINVAL;
...@@ -193,6 +181,49 @@ static int pcf50633_regulator_get_voltage(struct regulator_dev *rdev) ...@@ -193,6 +181,49 @@ static int pcf50633_regulator_get_voltage(struct regulator_dev *rdev)
return millivolts * 1000; return millivolts * 1000;
} }
static int pcf50633_regulator_get_voltage(struct regulator_dev *rdev)
{
struct pcf50633 *pcf;
int regulator_id;
u8 volt_bits, regnr;
pcf = rdev_get_drvdata(rdev);
regulator_id = rdev_get_id(rdev);
if (regulator_id >= PCF50633_NUM_REGULATORS)
return -EINVAL;
regnr = pcf50633_regulator_registers[regulator_id];
volt_bits = pcf50633_reg_read(pcf, regnr);
return pcf50633_regulator_voltage_value(regulator_id, volt_bits);
}
static int pcf50633_regulator_list_voltage(struct regulator_dev *rdev,
unsigned int index)
{
struct pcf50633 *pcf;
int regulator_id;
pcf = rdev_get_drvdata(rdev);
regulator_id = rdev_get_id(rdev);
switch (regulator_id) {
case PCF50633_REGULATOR_AUTO:
index += 0x2f;
break;
case PCF50633_REGULATOR_HCLDO:
index += 0x01;
break;
default:
break;
}
return pcf50633_regulator_voltage_value(regulator_id, index);
}
static int pcf50633_regulator_enable(struct regulator_dev *rdev) static int pcf50633_regulator_enable(struct regulator_dev *rdev)
{ {
struct pcf50633 *pcf = rdev_get_drvdata(rdev); struct pcf50633 *pcf = rdev_get_drvdata(rdev);
...@@ -246,6 +277,7 @@ static int pcf50633_regulator_is_enabled(struct regulator_dev *rdev) ...@@ -246,6 +277,7 @@ static int pcf50633_regulator_is_enabled(struct regulator_dev *rdev)
static struct regulator_ops pcf50633_regulator_ops = { static struct regulator_ops pcf50633_regulator_ops = {
.set_voltage = pcf50633_regulator_set_voltage, .set_voltage = pcf50633_regulator_set_voltage,
.get_voltage = pcf50633_regulator_get_voltage, .get_voltage = pcf50633_regulator_get_voltage,
.list_voltage = pcf50633_regulator_list_voltage,
.enable = pcf50633_regulator_enable, .enable = pcf50633_regulator_enable,
.disable = pcf50633_regulator_disable, .disable = pcf50633_regulator_disable,
.is_enabled = pcf50633_regulator_is_enabled, .is_enabled = pcf50633_regulator_is_enabled,
...@@ -253,27 +285,27 @@ static struct regulator_ops pcf50633_regulator_ops = { ...@@ -253,27 +285,27 @@ static struct regulator_ops pcf50633_regulator_ops = {
static struct regulator_desc regulators[] = { static struct regulator_desc regulators[] = {
[PCF50633_REGULATOR_AUTO] = [PCF50633_REGULATOR_AUTO] =
PCF50633_REGULATOR("auto", PCF50633_REGULATOR_AUTO), PCF50633_REGULATOR("auto", PCF50633_REGULATOR_AUTO, 80),
[PCF50633_REGULATOR_DOWN1] = [PCF50633_REGULATOR_DOWN1] =
PCF50633_REGULATOR("down1", PCF50633_REGULATOR_DOWN1), PCF50633_REGULATOR("down1", PCF50633_REGULATOR_DOWN1, 95),
[PCF50633_REGULATOR_DOWN2] = [PCF50633_REGULATOR_DOWN2] =
PCF50633_REGULATOR("down2", PCF50633_REGULATOR_DOWN2), PCF50633_REGULATOR("down2", PCF50633_REGULATOR_DOWN2, 95),
[PCF50633_REGULATOR_LDO1] = [PCF50633_REGULATOR_LDO1] =
PCF50633_REGULATOR("ldo1", PCF50633_REGULATOR_LDO1), PCF50633_REGULATOR("ldo1", PCF50633_REGULATOR_LDO1, 27),
[PCF50633_REGULATOR_LDO2] = [PCF50633_REGULATOR_LDO2] =
PCF50633_REGULATOR("ldo2", PCF50633_REGULATOR_LDO2), PCF50633_REGULATOR("ldo2", PCF50633_REGULATOR_LDO2, 27),
[PCF50633_REGULATOR_LDO3] = [PCF50633_REGULATOR_LDO3] =
PCF50633_REGULATOR("ldo3", PCF50633_REGULATOR_LDO3), PCF50633_REGULATOR("ldo3", PCF50633_REGULATOR_LDO3, 27),
[PCF50633_REGULATOR_LDO4] = [PCF50633_REGULATOR_LDO4] =
PCF50633_REGULATOR("ldo4", PCF50633_REGULATOR_LDO4), PCF50633_REGULATOR("ldo4", PCF50633_REGULATOR_LDO4, 27),
[PCF50633_REGULATOR_LDO5] = [PCF50633_REGULATOR_LDO5] =
PCF50633_REGULATOR("ldo5", PCF50633_REGULATOR_LDO5), PCF50633_REGULATOR("ldo5", PCF50633_REGULATOR_LDO5, 27),
[PCF50633_REGULATOR_LDO6] = [PCF50633_REGULATOR_LDO6] =
PCF50633_REGULATOR("ldo6", PCF50633_REGULATOR_LDO6), PCF50633_REGULATOR("ldo6", PCF50633_REGULATOR_LDO6, 27),
[PCF50633_REGULATOR_HCLDO] = [PCF50633_REGULATOR_HCLDO] =
PCF50633_REGULATOR("hcldo", PCF50633_REGULATOR_HCLDO), PCF50633_REGULATOR("hcldo", PCF50633_REGULATOR_HCLDO, 26),
[PCF50633_REGULATOR_MEMLDO] = [PCF50633_REGULATOR_MEMLDO] =
PCF50633_REGULATOR("memldo", PCF50633_REGULATOR_MEMLDO), PCF50633_REGULATOR("memldo", PCF50633_REGULATOR_MEMLDO, 0),
}; };
static int __devinit pcf50633_regulator_probe(struct platform_device *pdev) static int __devinit pcf50633_regulator_probe(struct platform_device *pdev)
......
/*
* tps65023-regulator.c
*
* Supports TPS65023 Regulator
*
* Copyright (C) 2009 Texas Instrument Incorporated - http://www.ti.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 version 2.
*
* This program is distributed "as is" WITHOUT ANY WARRANTY of any kind,
* whether express or implied; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/err.h>
#include <linux/platform_device.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <linux/i2c.h>
#include <linux/delay.h>
/* Register definitions */
#define TPS65023_REG_VERSION 0
#define TPS65023_REG_PGOODZ 1
#define TPS65023_REG_MASK 2
#define TPS65023_REG_REG_CTRL 3
#define TPS65023_REG_CON_CTRL 4
#define TPS65023_REG_CON_CTRL2 5
#define TPS65023_REG_DEF_CORE 6
#define TPS65023_REG_DEFSLEW 7
#define TPS65023_REG_LDO_CTRL 8
/* PGOODZ bitfields */
#define TPS65023_PGOODZ_PWRFAILZ BIT(7)
#define TPS65023_PGOODZ_LOWBATTZ BIT(6)
#define TPS65023_PGOODZ_VDCDC1 BIT(5)
#define TPS65023_PGOODZ_VDCDC2 BIT(4)
#define TPS65023_PGOODZ_VDCDC3 BIT(3)
#define TPS65023_PGOODZ_LDO2 BIT(2)
#define TPS65023_PGOODZ_LDO1 BIT(1)
/* MASK bitfields */
#define TPS65023_MASK_PWRFAILZ BIT(7)
#define TPS65023_MASK_LOWBATTZ BIT(6)
#define TPS65023_MASK_VDCDC1 BIT(5)
#define TPS65023_MASK_VDCDC2 BIT(4)
#define TPS65023_MASK_VDCDC3 BIT(3)
#define TPS65023_MASK_LDO2 BIT(2)
#define TPS65023_MASK_LDO1 BIT(1)
/* REG_CTRL bitfields */
#define TPS65023_REG_CTRL_VDCDC1_EN BIT(5)
#define TPS65023_REG_CTRL_VDCDC2_EN BIT(4)
#define TPS65023_REG_CTRL_VDCDC3_EN BIT(3)
#define TPS65023_REG_CTRL_LDO2_EN BIT(2)
#define TPS65023_REG_CTRL_LDO1_EN BIT(1)
/* LDO_CTRL bitfields */
#define TPS65023_LDO_CTRL_LDOx_SHIFT(ldo_id) ((ldo_id)*4)
#define TPS65023_LDO_CTRL_LDOx_MASK(ldo_id) (0xF0 >> ((ldo_id)*4))
/* Number of step-down converters available */
#define TPS65023_NUM_DCDC 3
/* Number of LDO voltage regulators available */
#define TPS65023_NUM_LDO 2
/* Number of total regulators available */
#define TPS65023_NUM_REGULATOR (TPS65023_NUM_DCDC + TPS65023_NUM_LDO)
/* DCDCs */
#define TPS65023_DCDC_1 0
#define TPS65023_DCDC_2 1
#define TPS65023_DCDC_3 2
/* LDOs */
#define TPS65023_LDO_1 3
#define TPS65023_LDO_2 4
#define TPS65023_MAX_REG_ID TPS65023_LDO_2
/* Supported voltage values for regulators */
static const u16 VDCDC1_VSEL_table[] = {
800, 825, 850, 875,
900, 925, 950, 975,
1000, 1025, 1050, 1075,
1100, 1125, 1150, 1175,
1200, 1225, 1250, 1275,
1300, 1325, 1350, 1375,
1400, 1425, 1450, 1475,
1500, 1525, 1550, 1600,
};
static const u16 LDO1_VSEL_table[] = {
1000, 1100, 1300, 1800,
2200, 2600, 2800, 3150,
};
static const u16 LDO2_VSEL_table[] = {
1050, 1200, 1300, 1800,
2500, 2800, 3000, 3300,
};
static unsigned int num_voltages[] = {ARRAY_SIZE(VDCDC1_VSEL_table),
0, 0, ARRAY_SIZE(LDO1_VSEL_table),
ARRAY_SIZE(LDO2_VSEL_table)};
/* Regulator specific details */
struct tps_info {
const char *name;
unsigned min_uV;
unsigned max_uV;
bool fixed;
u8 table_len;
const u16 *table;
};
/* PMIC details */
struct tps_pmic {
struct regulator_desc desc[TPS65023_NUM_REGULATOR];
struct i2c_client *client;
struct regulator_dev *rdev[TPS65023_NUM_REGULATOR];
const struct tps_info *info[TPS65023_NUM_REGULATOR];
struct mutex io_lock;
};
static inline int tps_65023_read(struct tps_pmic *tps, u8 reg)
{
return i2c_smbus_read_byte_data(tps->client, reg);
}
static inline int tps_65023_write(struct tps_pmic *tps, u8 reg, u8 val)
{
return i2c_smbus_write_byte_data(tps->client, reg, val);
}
static int tps_65023_set_bits(struct tps_pmic *tps, u8 reg, u8 mask)
{
int err, data;
mutex_lock(&tps->io_lock);
data = tps_65023_read(tps, reg);
if (data < 0) {
dev_err(&tps->client->dev, "Read from reg 0x%x failed\n", reg);
err = data;
goto out;
}
data |= mask;
err = tps_65023_write(tps, reg, data);
if (err)
dev_err(&tps->client->dev, "Write for reg 0x%x failed\n", reg);
out:
mutex_unlock(&tps->io_lock);
return err;
}
static int tps_65023_clear_bits(struct tps_pmic *tps, u8 reg, u8 mask)
{
int err, data;
mutex_lock(&tps->io_lock);
data = tps_65023_read(tps, reg);
if (data < 0) {
dev_err(&tps->client->dev, "Read from reg 0x%x failed\n", reg);
err = data;
goto out;
}
data &= ~mask;
err = tps_65023_write(tps, reg, data);
if (err)
dev_err(&tps->client->dev, "Write for reg 0x%x failed\n", reg);
out:
mutex_unlock(&tps->io_lock);
return err;
}
static int tps_65023_reg_read(struct tps_pmic *tps, u8 reg)
{
int data;
mutex_lock(&tps->io_lock);
data = tps_65023_read(tps, reg);
if (data < 0)
dev_err(&tps->client->dev, "Read from reg 0x%x failed\n", reg);
mutex_unlock(&tps->io_lock);
return data;
}
static int tps_65023_reg_write(struct tps_pmic *tps, u8 reg, u8 val)
{
int err;
mutex_lock(&tps->io_lock);
err = tps_65023_write(tps, reg, val);
if (err < 0)
dev_err(&tps->client->dev, "Write for reg 0x%x failed\n", reg);
mutex_unlock(&tps->io_lock);
return err;
}
static int tps65023_dcdc_is_enabled(struct regulator_dev *dev)
{
struct tps_pmic *tps = rdev_get_drvdata(dev);
int data, dcdc = rdev_get_id(dev);
u8 shift;
if (dcdc < TPS65023_DCDC_1 || dcdc > TPS65023_DCDC_3)
return -EINVAL;
shift = TPS65023_NUM_REGULATOR - dcdc;
data = tps_65023_reg_read(tps, TPS65023_REG_REG_CTRL);
if (data < 0)
return data;
else
return (data & 1<<shift) ? 1 : 0;
}
static int tps65023_ldo_is_enabled(struct regulator_dev *dev)
{
struct tps_pmic *tps = rdev_get_drvdata(dev);
int data, ldo = rdev_get_id(dev);
u8 shift;
if (ldo < TPS65023_LDO_1 || ldo > TPS65023_LDO_2)
return -EINVAL;
shift = (ldo == TPS65023_LDO_1 ? 1 : 2);
data = tps_65023_reg_read(tps, TPS65023_REG_REG_CTRL);
if (data < 0)
return data;
else
return (data & 1<<shift) ? 1 : 0;
}
static int tps65023_dcdc_enable(struct regulator_dev *dev)
{
struct tps_pmic *tps = rdev_get_drvdata(dev);
int dcdc = rdev_get_id(dev);
u8 shift;
if (dcdc < TPS65023_DCDC_1 || dcdc > TPS65023_DCDC_3)
return -EINVAL;
shift = TPS65023_NUM_REGULATOR - dcdc;
return tps_65023_set_bits(tps, TPS65023_REG_REG_CTRL, 1 << shift);
}
static int tps65023_dcdc_disable(struct regulator_dev *dev)
{
struct tps_pmic *tps = rdev_get_drvdata(dev);
int dcdc = rdev_get_id(dev);
u8 shift;
if (dcdc < TPS65023_DCDC_1 || dcdc > TPS65023_DCDC_3)
return -EINVAL;
shift = TPS65023_NUM_REGULATOR - dcdc;
return tps_65023_clear_bits(tps, TPS65023_REG_REG_CTRL, 1 << shift);
}
static int tps65023_ldo_enable(struct regulator_dev *dev)
{
struct tps_pmic *tps = rdev_get_drvdata(dev);
int ldo = rdev_get_id(dev);
u8 shift;
if (ldo < TPS65023_LDO_1 || ldo > TPS65023_LDO_2)
return -EINVAL;
shift = (ldo == TPS65023_LDO_1 ? 1 : 2);
return tps_65023_set_bits(tps, TPS65023_REG_REG_CTRL, 1 << shift);
}
static int tps65023_ldo_disable(struct regulator_dev *dev)
{
struct tps_pmic *tps = rdev_get_drvdata(dev);
int ldo = rdev_get_id(dev);
u8 shift;
if (ldo < TPS65023_LDO_1 || ldo > TPS65023_LDO_2)
return -EINVAL;
shift = (ldo == TPS65023_LDO_1 ? 1 : 2);
return tps_65023_clear_bits(tps, TPS65023_REG_REG_CTRL, 1 << shift);
}
static int tps65023_dcdc_get_voltage(struct regulator_dev *dev)
{
struct tps_pmic *tps = rdev_get_drvdata(dev);
int data, dcdc = rdev_get_id(dev);
if (dcdc < TPS65023_DCDC_1 || dcdc > TPS65023_DCDC_3)
return -EINVAL;
if (dcdc == TPS65023_DCDC_1) {
data = tps_65023_reg_read(tps, TPS65023_REG_DEF_CORE);
if (data < 0)
return data;
data &= (tps->info[dcdc]->table_len - 1);
return tps->info[dcdc]->table[data] * 1000;
} else
return tps->info[dcdc]->min_uV;
}
static int tps65023_dcdc_set_voltage(struct regulator_dev *dev,
int min_uV, int max_uV)
{
struct tps_pmic *tps = rdev_get_drvdata(dev);
int dcdc = rdev_get_id(dev);
int vsel;
if (dcdc != TPS65023_DCDC_1)
return -EINVAL;
if (min_uV < tps->info[dcdc]->min_uV
|| min_uV > tps->info[dcdc]->max_uV)
return -EINVAL;
if (max_uV < tps->info[dcdc]->min_uV
|| max_uV > tps->info[dcdc]->max_uV)
return -EINVAL;
for (vsel = 0; vsel < tps->info[dcdc]->table_len; vsel++) {
int mV = tps->info[dcdc]->table[vsel];
int uV = mV * 1000;
/* Break at the first in-range value */
if (min_uV <= uV && uV <= max_uV)
break;
}
/* write to the register in case we found a match */
if (vsel == tps->info[dcdc]->table_len)
return -EINVAL;
else
return tps_65023_reg_write(tps, TPS65023_REG_DEF_CORE, vsel);
}
static int tps65023_ldo_get_voltage(struct regulator_dev *dev)
{
struct tps_pmic *tps = rdev_get_drvdata(dev);
int data, ldo = rdev_get_id(dev);
if (ldo < TPS65023_LDO_1 || ldo > TPS65023_LDO_2)
return -EINVAL;
data = tps_65023_reg_read(tps, TPS65023_REG_LDO_CTRL);
if (data < 0)
return data;
data >>= (TPS65023_LDO_CTRL_LDOx_SHIFT(ldo - TPS65023_LDO_1));
data &= (tps->info[ldo]->table_len - 1);
return tps->info[ldo]->table[data] * 1000;
}
static int tps65023_ldo_set_voltage(struct regulator_dev *dev,
int min_uV, int max_uV)
{
struct tps_pmic *tps = rdev_get_drvdata(dev);
int data, vsel, ldo = rdev_get_id(dev);
if (ldo < TPS65023_LDO_1 || ldo > TPS65023_LDO_2)
return -EINVAL;
if (min_uV < tps->info[ldo]->min_uV || min_uV > tps->info[ldo]->max_uV)
return -EINVAL;
if (max_uV < tps->info[ldo]->min_uV || max_uV > tps->info[ldo]->max_uV)
return -EINVAL;
for (vsel = 0; vsel < tps->info[ldo]->table_len; vsel++) {
int mV = tps->info[ldo]->table[vsel];
int uV = mV * 1000;
/* Break at the first in-range value */
if (min_uV <= uV && uV <= max_uV)
break;
}
if (vsel == tps->info[ldo]->table_len)
return -EINVAL;
data = tps_65023_reg_read(tps, TPS65023_REG_LDO_CTRL);
if (data < 0)
return data;
data &= TPS65023_LDO_CTRL_LDOx_MASK(ldo - TPS65023_LDO_1);
data |= (vsel << (TPS65023_LDO_CTRL_LDOx_SHIFT(ldo - TPS65023_LDO_1)));
return tps_65023_reg_write(tps, TPS65023_REG_LDO_CTRL, data);
}
static int tps65023_dcdc_list_voltage(struct regulator_dev *dev,
unsigned selector)
{
struct tps_pmic *tps = rdev_get_drvdata(dev);
int dcdc = rdev_get_id(dev);
if (dcdc < TPS65023_DCDC_1 || dcdc > TPS65023_DCDC_3)
return -EINVAL;
if (dcdc == TPS65023_DCDC_1) {
if (selector >= tps->info[dcdc]->table_len)
return -EINVAL;
else
return tps->info[dcdc]->table[selector] * 1000;
} else
return tps->info[dcdc]->min_uV;
}
static int tps65023_ldo_list_voltage(struct regulator_dev *dev,
unsigned selector)
{
struct tps_pmic *tps = rdev_get_drvdata(dev);
int ldo = rdev_get_id(dev);
if (ldo < TPS65023_LDO_1 || ldo > TPS65023_LDO_2)
return -EINVAL;
if (selector >= tps->info[ldo]->table_len)
return -EINVAL;
else
return tps->info[ldo]->table[selector] * 1000;
}
/* Operations permitted on VDCDCx */
static struct regulator_ops tps65023_dcdc_ops = {
.is_enabled = tps65023_dcdc_is_enabled,
.enable = tps65023_dcdc_enable,
.disable = tps65023_dcdc_disable,
.get_voltage = tps65023_dcdc_get_voltage,
.set_voltage = tps65023_dcdc_set_voltage,
.list_voltage = tps65023_dcdc_list_voltage,
};
/* Operations permitted on LDOx */
static struct regulator_ops tps65023_ldo_ops = {
.is_enabled = tps65023_ldo_is_enabled,
.enable = tps65023_ldo_enable,
.disable = tps65023_ldo_disable,
.get_voltage = tps65023_ldo_get_voltage,
.set_voltage = tps65023_ldo_set_voltage,
.list_voltage = tps65023_ldo_list_voltage,
};
static
int 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;
struct regulator_init_data *init_data;
struct regulator_dev *rdev;
struct tps_pmic *tps;
int i;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -EIO;
/**
* init_data points to array of regulator_init structures
* coming from the board-evm file.
*/
init_data = client->dev.platform_data;
if (!init_data)
return -EIO;
tps = kzalloc(sizeof(*tps), GFP_KERNEL);
if (!tps)
return -ENOMEM;
mutex_init(&tps->io_lock);
/* common for all regulators */
tps->client = client;
for (i = 0; i < TPS65023_NUM_REGULATOR; i++, info++, init_data++) {
/* Store regulator specific information */
tps->info[i] = info;
tps->desc[i].name = info->name;
tps->desc[i].id = desc_id++;
tps->desc[i].n_voltages = num_voltages[i];
tps->desc[i].ops = (i > TPS65023_DCDC_3 ?
&tps65023_ldo_ops : &tps65023_dcdc_ops);
tps->desc[i].type = REGULATOR_VOLTAGE;
tps->desc[i].owner = THIS_MODULE;
/* Register the regulators */
rdev = regulator_register(&tps->desc[i], &client->dev,
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);
}
/* Save regulator for cleanup */
tps->rdev[i] = rdev;
}
i2c_set_clientdata(client, tps);
return 0;
}
/**
* tps_65023_remove - TPS65023 driver i2c remove handler
* @client: i2c driver client device structure
*
* Unregister TPS driver as an i2c client device driver
*/
static int __devexit tps_65023_remove(struct i2c_client *client)
{
struct tps_pmic *tps = i2c_get_clientdata(client);
int i;
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;
}
static const struct tps_info tps65023_regs[] = {
{
.name = "VDCDC1",
.min_uV = 800000,
.max_uV = 1600000,
.table_len = ARRAY_SIZE(VDCDC1_VSEL_table),
.table = VDCDC1_VSEL_table,
},
{
.name = "VDCDC2",
.min_uV = 3300000,
.max_uV = 3300000,
.fixed = 1,
},
{
.name = "VDCDC3",
.min_uV = 1800000,
.max_uV = 1800000,
.fixed = 1,
},
{
.name = "LDO1",
.min_uV = 1000000,
.max_uV = 3150000,
.table_len = ARRAY_SIZE(LDO1_VSEL_table),
.table = LDO1_VSEL_table,
},
{
.name = "LDO2",
.min_uV = 1050000,
.max_uV = 3300000,
.table_len = ARRAY_SIZE(LDO2_VSEL_table),
.table = LDO2_VSEL_table,
},
};
static const struct i2c_device_id tps_65023_id[] = {
{.name = "tps65023",
.driver_data = (unsigned long) tps65023_regs,},
{ },
};
MODULE_DEVICE_TABLE(i2c, tps_65023_id);
static struct i2c_driver tps_65023_i2c_driver = {
.driver = {
.name = "tps65023",
.owner = THIS_MODULE,
},
.probe = tps_65023_probe,
.remove = __devexit_p(tps_65023_remove),
.id_table = tps_65023_id,
};
/**
* tps_65023_init
*
* Module init function
*/
static int __init tps_65023_init(void)
{
return i2c_add_driver(&tps_65023_i2c_driver);
}
subsys_initcall(tps_65023_init);
/**
* tps_65023_cleanup
*
* Module exit function
*/
static void __exit tps_65023_cleanup(void)
{
i2c_del_driver(&tps_65023_i2c_driver);
}
module_exit(tps_65023_cleanup);
MODULE_AUTHOR("Texas Instruments");
MODULE_DESCRIPTION("TPS65023 voltage regulator driver");
MODULE_LICENSE("GPL v2");
/*
* tps6507x-regulator.c
*
* Regulator driver for TPS65073 PMIC
*
* Copyright (C) 2009 Texas Instrument Incorporated - http://www.ti.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 version 2.
*
* This program is distributed "as is" WITHOUT ANY WARRANTY of any kind,
* whether express or implied; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/err.h>
#include <linux/platform_device.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <linux/i2c.h>
#include <linux/delay.h>
/* Register definitions */
#define TPS6507X_REG_PPATH1 0X01
#define TPS6507X_REG_INT 0X02
#define TPS6507X_REG_CHGCONFIG0 0X03
#define TPS6507X_REG_CHGCONFIG1 0X04
#define TPS6507X_REG_CHGCONFIG2 0X05
#define TPS6507X_REG_CHGCONFIG3 0X06
#define TPS6507X_REG_REG_ADCONFIG 0X07
#define TPS6507X_REG_TSCMODE 0X08
#define TPS6507X_REG_ADRESULT_1 0X09
#define TPS6507X_REG_ADRESULT_2 0X0A
#define TPS6507X_REG_PGOOD 0X0B
#define TPS6507X_REG_PGOODMASK 0X0C
#define TPS6507X_REG_CON_CTRL1 0X0D
#define TPS6507X_REG_CON_CTRL2 0X0E
#define TPS6507X_REG_CON_CTRL3 0X0F
#define TPS6507X_REG_DEFDCDC1 0X10
#define TPS6507X_REG_DEFDCDC2_LOW 0X11
#define TPS6507X_REG_DEFDCDC2_HIGH 0X12
#define TPS6507X_REG_DEFDCDC3_LOW 0X13
#define TPS6507X_REG_DEFDCDC3_HIGH 0X14
#define TPS6507X_REG_DEFSLEW 0X15
#define TPS6507X_REG_LDO_CTRL1 0X16
#define TPS6507X_REG_DEFLDO2 0X17
#define TPS6507X_REG_WLED_CTRL1 0X18
#define TPS6507X_REG_WLED_CTRL2 0X19
/* CON_CTRL1 bitfields */
#define TPS6507X_CON_CTRL1_DCDC1_ENABLE BIT(4)
#define TPS6507X_CON_CTRL1_DCDC2_ENABLE BIT(3)
#define TPS6507X_CON_CTRL1_DCDC3_ENABLE BIT(2)
#define TPS6507X_CON_CTRL1_LDO1_ENABLE BIT(1)
#define TPS6507X_CON_CTRL1_LDO2_ENABLE BIT(0)
/* DEFDCDC1 bitfields */
#define TPS6507X_DEFDCDC1_DCDC1_EXT_ADJ_EN BIT(7)
#define TPS6507X_DEFDCDC1_DCDC1_MASK 0X3F
/* DEFDCDC2_LOW bitfields */
#define TPS6507X_DEFDCDC2_LOW_DCDC2_MASK 0X3F
/* DEFDCDC2_HIGH bitfields */
#define TPS6507X_DEFDCDC2_HIGH_DCDC2_MASK 0X3F
/* DEFDCDC3_LOW bitfields */
#define TPS6507X_DEFDCDC3_LOW_DCDC3_MASK 0X3F
/* DEFDCDC3_HIGH bitfields */
#define TPS6507X_DEFDCDC3_HIGH_DCDC3_MASK 0X3F
/* TPS6507X_REG_LDO_CTRL1 bitfields */
#define TPS6507X_REG_LDO_CTRL1_LDO1_MASK 0X0F
/* TPS6507X_REG_DEFLDO2 bitfields */
#define TPS6507X_REG_DEFLDO2_LDO2_MASK 0X3F
/* VDCDC MASK */
#define TPS6507X_DEFDCDCX_DCDC_MASK 0X3F
/* DCDC's */
#define TPS6507X_DCDC_1 0
#define TPS6507X_DCDC_2 1
#define TPS6507X_DCDC_3 2
/* LDOs */
#define TPS6507X_LDO_1 3
#define TPS6507X_LDO_2 4
#define TPS6507X_MAX_REG_ID TPS6507X_LDO_2
/* Number of step-down converters available */
#define TPS6507X_NUM_DCDC 3
/* Number of LDO voltage regulators available */
#define TPS6507X_NUM_LDO 2
/* Number of total regulators available */
#define TPS6507X_NUM_REGULATOR (TPS6507X_NUM_DCDC + TPS6507X_NUM_LDO)
/* Supported voltage values for regulators (in milliVolts) */
static const u16 VDCDCx_VSEL_table[] = {
725, 750, 775, 800,
825, 850, 875, 900,
925, 950, 975, 1000,
1025, 1050, 1075, 1100,
1125, 1150, 1175, 1200,
1225, 1250, 1275, 1300,
1325, 1350, 1375, 1400,
1425, 1450, 1475, 1500,
1550, 1600, 1650, 1700,
1750, 1800, 1850, 1900,
1950, 2000, 2050, 2100,
2150, 2200, 2250, 2300,
2350, 2400, 2450, 2500,
2550, 2600, 2650, 2700,
2750, 2800, 2850, 2900,
3000, 3100, 3200, 3300,
};
static const u16 LDO1_VSEL_table[] = {
1000, 1100, 1200, 1250,
1300, 1350, 1400, 1500,
1600, 1800, 2500, 2750,
2800, 3000, 3100, 3300,
};
static const u16 LDO2_VSEL_table[] = {
725, 750, 775, 800,
825, 850, 875, 900,
925, 950, 975, 1000,
1025, 1050, 1075, 1100,
1125, 1150, 1175, 1200,
1225, 1250, 1275, 1300,
1325, 1350, 1375, 1400,
1425, 1450, 1475, 1500,
1550, 1600, 1650, 1700,
1750, 1800, 1850, 1900,
1950, 2000, 2050, 2100,
2150, 2200, 2250, 2300,
2350, 2400, 2450, 2500,
2550, 2600, 2650, 2700,
2750, 2800, 2850, 2900,
3000, 3100, 3200, 3300,
};
static unsigned int num_voltages[] = {ARRAY_SIZE(VDCDCx_VSEL_table),
ARRAY_SIZE(VDCDCx_VSEL_table),
ARRAY_SIZE(VDCDCx_VSEL_table),
ARRAY_SIZE(LDO1_VSEL_table),
ARRAY_SIZE(LDO2_VSEL_table)};
struct tps_info {
const char *name;
unsigned min_uV;
unsigned max_uV;
u8 table_len;
const u16 *table;
};
struct tps_pmic {
struct regulator_desc desc[TPS6507X_NUM_REGULATOR];
struct i2c_client *client;
struct regulator_dev *rdev[TPS6507X_NUM_REGULATOR];
const struct tps_info *info[TPS6507X_NUM_REGULATOR];
struct mutex io_lock;
};
static inline int tps_6507x_read(struct tps_pmic *tps, u8 reg)
{
return i2c_smbus_read_byte_data(tps->client, reg);
}
static inline int tps_6507x_write(struct tps_pmic *tps, u8 reg, u8 val)
{
return i2c_smbus_write_byte_data(tps->client, reg, val);
}
static int tps_6507x_set_bits(struct tps_pmic *tps, u8 reg, u8 mask)
{
int err, data;
mutex_lock(&tps->io_lock);
data = tps_6507x_read(tps, reg);
if (data < 0) {
dev_err(&tps->client->dev, "Read from reg 0x%x failed\n", reg);
err = data;
goto out;
}
data |= mask;
err = tps_6507x_write(tps, reg, data);
if (err)
dev_err(&tps->client->dev, "Write for reg 0x%x failed\n", reg);
out:
mutex_unlock(&tps->io_lock);
return err;
}
static int tps_6507x_clear_bits(struct tps_pmic *tps, u8 reg, u8 mask)
{
int err, data;
mutex_lock(&tps->io_lock);
data = tps_6507x_read(tps, reg);
if (data < 0) {
dev_err(&tps->client->dev, "Read from reg 0x%x failed\n", reg);
err = data;
goto out;
}
data &= ~mask;
err = tps_6507x_write(tps, reg, data);
if (err)
dev_err(&tps->client->dev, "Write for reg 0x%x failed\n", reg);
out:
mutex_unlock(&tps->io_lock);
return err;
}
static int tps_6507x_reg_read(struct tps_pmic *tps, u8 reg)
{
int data;
mutex_lock(&tps->io_lock);
data = tps_6507x_read(tps, reg);
if (data < 0)
dev_err(&tps->client->dev, "Read from reg 0x%x failed\n", reg);
mutex_unlock(&tps->io_lock);
return data;
}
static int tps_6507x_reg_write(struct tps_pmic *tps, u8 reg, u8 val)
{
int err;
mutex_lock(&tps->io_lock);
err = tps_6507x_write(tps, reg, val);
if (err < 0)
dev_err(&tps->client->dev, "Write for reg 0x%x failed\n", reg);
mutex_unlock(&tps->io_lock);
return err;
}
static int tps6507x_dcdc_is_enabled(struct regulator_dev *dev)
{
struct tps_pmic *tps = rdev_get_drvdata(dev);
int data, dcdc = rdev_get_id(dev);
u8 shift;
if (dcdc < TPS6507X_DCDC_1 || dcdc > TPS6507X_DCDC_3)
return -EINVAL;
shift = TPS6507X_MAX_REG_ID - dcdc;
data = tps_6507x_reg_read(tps, TPS6507X_REG_CON_CTRL1);
if (data < 0)
return data;
else
return (data & 1<<shift) ? 1 : 0;
}
static int tps6507x_ldo_is_enabled(struct regulator_dev *dev)
{
struct tps_pmic *tps = rdev_get_drvdata(dev);
int data, ldo = rdev_get_id(dev);
u8 shift;
if (ldo < TPS6507X_LDO_1 || ldo > TPS6507X_LDO_2)
return -EINVAL;
shift = TPS6507X_MAX_REG_ID - ldo;
data = tps_6507x_reg_read(tps, TPS6507X_REG_CON_CTRL1);
if (data < 0)
return data;
else
return (data & 1<<shift) ? 1 : 0;
}
static int tps6507x_dcdc_enable(struct regulator_dev *dev)
{
struct tps_pmic *tps = rdev_get_drvdata(dev);
int dcdc = rdev_get_id(dev);
u8 shift;
if (dcdc < TPS6507X_DCDC_1 || dcdc > TPS6507X_DCDC_3)
return -EINVAL;
shift = TPS6507X_MAX_REG_ID - dcdc;
return tps_6507x_set_bits(tps, TPS6507X_REG_CON_CTRL1, 1 << shift);
}
static int tps6507x_dcdc_disable(struct regulator_dev *dev)
{
struct tps_pmic *tps = rdev_get_drvdata(dev);
int dcdc = rdev_get_id(dev);
u8 shift;
if (dcdc < TPS6507X_DCDC_1 || dcdc > TPS6507X_DCDC_3)
return -EINVAL;
shift = TPS6507X_MAX_REG_ID - dcdc;
return tps_6507x_clear_bits(tps, TPS6507X_REG_CON_CTRL1, 1 << shift);
}
static int tps6507x_ldo_enable(struct regulator_dev *dev)
{
struct tps_pmic *tps = rdev_get_drvdata(dev);
int ldo = rdev_get_id(dev);
u8 shift;
if (ldo < TPS6507X_LDO_1 || ldo > TPS6507X_LDO_2)
return -EINVAL;
shift = TPS6507X_MAX_REG_ID - ldo;
return tps_6507x_set_bits(tps, TPS6507X_REG_CON_CTRL1, 1 << shift);
}
static int tps6507x_ldo_disable(struct regulator_dev *dev)
{
struct tps_pmic *tps = rdev_get_drvdata(dev);
int ldo = rdev_get_id(dev);
u8 shift;
if (ldo < TPS6507X_LDO_1 || ldo > TPS6507X_LDO_2)
return -EINVAL;
shift = TPS6507X_MAX_REG_ID - ldo;
return tps_6507x_clear_bits(tps, TPS6507X_REG_CON_CTRL1, 1 << shift);
}
static int tps6507x_dcdc_get_voltage(struct regulator_dev *dev)
{
struct tps_pmic *tps = rdev_get_drvdata(dev);
int data, dcdc = rdev_get_id(dev);
u8 reg;
switch (dcdc) {
case TPS6507X_DCDC_1:
reg = TPS6507X_REG_DEFDCDC1;
break;
case TPS6507X_DCDC_2:
reg = TPS6507X_REG_DEFDCDC2_LOW;
break;
case TPS6507X_DCDC_3:
reg = TPS6507X_REG_DEFDCDC3_LOW;
break;
default:
return -EINVAL;
}
data = tps_6507x_reg_read(tps, reg);
if (data < 0)
return data;
data &= TPS6507X_DEFDCDCX_DCDC_MASK;
return tps->info[dcdc]->table[data] * 1000;
}
static int tps6507x_dcdc_set_voltage(struct regulator_dev *dev,
int min_uV, int max_uV)
{
struct tps_pmic *tps = rdev_get_drvdata(dev);
int data, vsel, dcdc = rdev_get_id(dev);
u8 reg;
switch (dcdc) {
case TPS6507X_DCDC_1:
reg = TPS6507X_REG_DEFDCDC1;
break;
case TPS6507X_DCDC_2:
reg = TPS6507X_REG_DEFDCDC2_LOW;
break;
case TPS6507X_DCDC_3:
reg = TPS6507X_REG_DEFDCDC3_LOW;
break;
default:
return -EINVAL;
}
if (min_uV < tps->info[dcdc]->min_uV
|| min_uV > tps->info[dcdc]->max_uV)
return -EINVAL;
if (max_uV < tps->info[dcdc]->min_uV
|| max_uV > tps->info[dcdc]->max_uV)
return -EINVAL;
for (vsel = 0; vsel < tps->info[dcdc]->table_len; vsel++) {
int mV = tps->info[dcdc]->table[vsel];
int uV = mV * 1000;
/* Break at the first in-range value */
if (min_uV <= uV && uV <= max_uV)
break;
}
/* write to the register in case we found a match */
if (vsel == tps->info[dcdc]->table_len)
return -EINVAL;
data = tps_6507x_reg_read(tps, reg);
if (data < 0)
return data;
data &= ~TPS6507X_DEFDCDCX_DCDC_MASK;
data |= vsel;
return tps_6507x_reg_write(tps, reg, data);
}
static int tps6507x_ldo_get_voltage(struct regulator_dev *dev)
{
struct tps_pmic *tps = rdev_get_drvdata(dev);
int data, ldo = rdev_get_id(dev);
u8 reg, mask;
if (ldo < TPS6507X_LDO_1 || ldo > TPS6507X_LDO_2)
return -EINVAL;
else {
reg = (ldo == TPS6507X_LDO_1 ?
TPS6507X_REG_LDO_CTRL1 : TPS6507X_REG_DEFLDO2);
mask = (ldo == TPS6507X_LDO_1 ?
TPS6507X_REG_LDO_CTRL1_LDO1_MASK :
TPS6507X_REG_DEFLDO2_LDO2_MASK);
}
data = tps_6507x_reg_read(tps, reg);
if (data < 0)
return data;
data &= mask;
return tps->info[ldo]->table[data] * 1000;
}
static int tps6507x_ldo_set_voltage(struct regulator_dev *dev,
int min_uV, int max_uV)
{
struct tps_pmic *tps = rdev_get_drvdata(dev);
int data, vsel, ldo = rdev_get_id(dev);
u8 reg, mask;
if (ldo < TPS6507X_LDO_1 || ldo > TPS6507X_LDO_2)
return -EINVAL;
else {
reg = (ldo == TPS6507X_LDO_1 ?
TPS6507X_REG_LDO_CTRL1 : TPS6507X_REG_DEFLDO2);
mask = (ldo == TPS6507X_LDO_1 ?
TPS6507X_REG_LDO_CTRL1_LDO1_MASK :
TPS6507X_REG_DEFLDO2_LDO2_MASK);
}
if (min_uV < tps->info[ldo]->min_uV || min_uV > tps->info[ldo]->max_uV)
return -EINVAL;
if (max_uV < tps->info[ldo]->min_uV || max_uV > tps->info[ldo]->max_uV)
return -EINVAL;
for (vsel = 0; vsel < tps->info[ldo]->table_len; vsel++) {
int mV = tps->info[ldo]->table[vsel];
int uV = mV * 1000;
/* Break at the first in-range value */
if (min_uV <= uV && uV <= max_uV)
break;
}
if (vsel == tps->info[ldo]->table_len)
return -EINVAL;
data = tps_6507x_reg_read(tps, reg);
if (data < 0)
return data;
data &= ~mask;
data |= vsel;
return tps_6507x_reg_write(tps, reg, data);
}
static int tps6507x_dcdc_list_voltage(struct regulator_dev *dev,
unsigned selector)
{
struct tps_pmic *tps = rdev_get_drvdata(dev);
int dcdc = rdev_get_id(dev);
if (dcdc < TPS6507X_DCDC_1 || dcdc > TPS6507X_DCDC_3)
return -EINVAL;
if (selector >= tps->info[dcdc]->table_len)
return -EINVAL;
else
return tps->info[dcdc]->table[selector] * 1000;
}
static int tps6507x_ldo_list_voltage(struct regulator_dev *dev,
unsigned selector)
{
struct tps_pmic *tps = rdev_get_drvdata(dev);
int ldo = rdev_get_id(dev);
if (ldo < TPS6507X_LDO_1 || ldo > TPS6507X_LDO_2)
return -EINVAL;
if (selector >= tps->info[ldo]->table_len)
return -EINVAL;
else
return tps->info[ldo]->table[selector] * 1000;
}
/* Operations permitted on VDCDCx */
static struct regulator_ops tps6507x_dcdc_ops = {
.is_enabled = tps6507x_dcdc_is_enabled,
.enable = tps6507x_dcdc_enable,
.disable = tps6507x_dcdc_disable,
.get_voltage = tps6507x_dcdc_get_voltage,
.set_voltage = tps6507x_dcdc_set_voltage,
.list_voltage = tps6507x_dcdc_list_voltage,
};
/* Operations permitted on LDOx */
static struct regulator_ops tps6507x_ldo_ops = {
.is_enabled = tps6507x_ldo_is_enabled,
.enable = tps6507x_ldo_enable,
.disable = tps6507x_ldo_disable,
.get_voltage = tps6507x_ldo_get_voltage,
.set_voltage = tps6507x_ldo_set_voltage,
.list_voltage = tps6507x_ldo_list_voltage,
};
static
int 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;
struct regulator_init_data *init_data;
struct regulator_dev *rdev;
struct tps_pmic *tps;
int i;
if (!i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_BYTE_DATA))
return -EIO;
/**
* init_data points to array of regulator_init structures
* coming from the board-evm file.
*/
init_data = client->dev.platform_data;
if (!init_data)
return -EIO;
tps = kzalloc(sizeof(*tps), GFP_KERNEL);
if (!tps)
return -ENOMEM;
mutex_init(&tps->io_lock);
/* common for all regulators */
tps->client = client;
for (i = 0; i < TPS6507X_NUM_REGULATOR; i++, info++, init_data++) {
/* Register the regulators */
tps->info[i] = info;
tps->desc[i].name = info->name;
tps->desc[i].id = desc_id++;
tps->desc[i].n_voltages = num_voltages[i];
tps->desc[i].ops = (i > TPS6507X_DCDC_3 ?
&tps6507x_ldo_ops : &tps6507x_dcdc_ops);
tps->desc[i].type = REGULATOR_VOLTAGE;
tps->desc[i].owner = THIS_MODULE;
rdev = regulator_register(&tps->desc[i],
&client->dev, 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);
}
/* Save regulator for cleanup */
tps->rdev[i] = rdev;
}
i2c_set_clientdata(client, tps);
return 0;
}
/**
* tps_6507x_remove - TPS6507x driver i2c remove handler
* @client: i2c driver client device structure
*
* Unregister TPS driver as an i2c client device driver
*/
static int __devexit tps_6507x_remove(struct i2c_client *client)
{
struct tps_pmic *tps = i2c_get_clientdata(client);
int i;
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;
}
static const struct tps_info tps6507x_regs[] = {
{
.name = "VDCDC1",
.min_uV = 725000,
.max_uV = 3300000,
.table_len = ARRAY_SIZE(VDCDCx_VSEL_table),
.table = VDCDCx_VSEL_table,
},
{
.name = "VDCDC2",
.min_uV = 725000,
.max_uV = 3300000,
.table_len = ARRAY_SIZE(VDCDCx_VSEL_table),
.table = VDCDCx_VSEL_table,
},
{
.name = "VDCDC3",
.min_uV = 725000,
.max_uV = 3300000,
.table_len = ARRAY_SIZE(VDCDCx_VSEL_table),
.table = VDCDCx_VSEL_table,
},
{
.name = "LDO1",
.min_uV = 1000000,
.max_uV = 3300000,
.table_len = ARRAY_SIZE(LDO1_VSEL_table),
.table = LDO1_VSEL_table,
},
{
.name = "LDO2",
.min_uV = 725000,
.max_uV = 3300000,
.table_len = ARRAY_SIZE(LDO2_VSEL_table),
.table = LDO2_VSEL_table,
},
};
static const struct i2c_device_id tps_6507x_id[] = {
{.name = "tps6507x",
.driver_data = (unsigned long) tps6507x_regs,},
{ },
};
MODULE_DEVICE_TABLE(i2c, tps_6507x_id);
static struct i2c_driver tps_6507x_i2c_driver = {
.driver = {
.name = "tps6507x",
.owner = THIS_MODULE,
},
.probe = tps_6507x_probe,
.remove = __devexit_p(tps_6507x_remove),
.id_table = tps_6507x_id,
};
/**
* tps_6507x_init
*
* Module init function
*/
static int __init tps_6507x_init(void)
{
return i2c_add_driver(&tps_6507x_i2c_driver);
}
subsys_initcall(tps_6507x_init);
/**
* tps_6507x_cleanup
*
* Module exit function
*/
static void __exit tps_6507x_cleanup(void)
{
i2c_del_driver(&tps_6507x_i2c_driver);
}
module_exit(tps_6507x_cleanup);
MODULE_AUTHOR("Texas Instruments");
MODULE_DESCRIPTION("TPS6507x voltage regulator driver");
MODULE_LICENSE("GPL v2");
...@@ -93,16 +93,21 @@ static ssize_t reg_set_state(struct device *dev, struct device_attribute *attr, ...@@ -93,16 +93,21 @@ static ssize_t reg_set_state(struct device *dev, struct device_attribute *attr,
static DEVICE_ATTR(name, 0444, reg_show_name, NULL); static DEVICE_ATTR(name, 0444, reg_show_name, NULL);
static DEVICE_ATTR(state, 0644, reg_show_state, reg_set_state); static DEVICE_ATTR(state, 0644, reg_show_state, reg_set_state);
static struct device_attribute *attributes[] = { static struct attribute *attributes[] = {
&dev_attr_name, &dev_attr_name.attr,
&dev_attr_state, &dev_attr_state.attr,
NULL,
};
static const struct attribute_group attr_group = {
.attrs = attributes,
}; };
static int regulator_userspace_consumer_probe(struct platform_device *pdev) static int regulator_userspace_consumer_probe(struct platform_device *pdev)
{ {
struct regulator_userspace_consumer_data *pdata; struct regulator_userspace_consumer_data *pdata;
struct userspace_consumer_data *drvdata; struct userspace_consumer_data *drvdata;
int ret, i; int ret;
pdata = pdev->dev.platform_data; pdata = pdev->dev.platform_data;
if (!pdata) if (!pdata)
...@@ -125,31 +130,29 @@ static int regulator_userspace_consumer_probe(struct platform_device *pdev) ...@@ -125,31 +130,29 @@ static int regulator_userspace_consumer_probe(struct platform_device *pdev)
goto err_alloc_supplies; goto err_alloc_supplies;
} }
for (i = 0; i < ARRAY_SIZE(attributes); i++) { ret = sysfs_create_group(&pdev->dev.kobj, &attr_group);
ret = device_create_file(&pdev->dev, attributes[i]); if (ret != 0)
if (ret != 0) goto err_create_attrs;
goto err_create_attrs;
}
if (pdata->init_on) if (pdata->init_on) {
ret = regulator_bulk_enable(drvdata->num_supplies, ret = regulator_bulk_enable(drvdata->num_supplies,
drvdata->supplies); drvdata->supplies);
if (ret) {
drvdata->enabled = pdata->init_on; dev_err(&pdev->dev,
"Failed to set initial state: %d\n", ret);
if (ret) { goto err_enable;
dev_err(&pdev->dev, "Failed to set initial state: %d\n", ret); }
goto err_create_attrs;
} }
drvdata->enabled = pdata->init_on;
platform_set_drvdata(pdev, drvdata); platform_set_drvdata(pdev, drvdata);
return 0; return 0;
err_create_attrs: err_enable:
for (i = 0; i < ARRAY_SIZE(attributes); i++) sysfs_remove_group(&pdev->dev.kobj, &attr_group);
device_remove_file(&pdev->dev, attributes[i]);
err_create_attrs:
regulator_bulk_free(drvdata->num_supplies, drvdata->supplies); regulator_bulk_free(drvdata->num_supplies, drvdata->supplies);
err_alloc_supplies: err_alloc_supplies:
...@@ -160,10 +163,8 @@ static int regulator_userspace_consumer_probe(struct platform_device *pdev) ...@@ -160,10 +163,8 @@ static int regulator_userspace_consumer_probe(struct platform_device *pdev)
static int regulator_userspace_consumer_remove(struct platform_device *pdev) static int regulator_userspace_consumer_remove(struct platform_device *pdev)
{ {
struct userspace_consumer_data *data = platform_get_drvdata(pdev); struct userspace_consumer_data *data = platform_get_drvdata(pdev);
int i;
for (i = 0; i < ARRAY_SIZE(attributes); i++) sysfs_remove_group(&pdev->dev.kobj, &attr_group);
device_remove_file(&pdev->dev, attributes[i]);
if (data->enabled) if (data->enabled)
regulator_bulk_disable(data->num_supplies, data->supplies); regulator_bulk_disable(data->num_supplies, data->supplies);
......
...@@ -27,71 +27,81 @@ struct virtual_consumer_data { ...@@ -27,71 +27,81 @@ struct virtual_consumer_data {
unsigned int mode; unsigned int mode;
}; };
static void update_voltage_constraints(struct virtual_consumer_data *data) static void update_voltage_constraints(struct device *dev,
struct virtual_consumer_data *data)
{ {
int ret; int ret;
if (data->min_uV && data->max_uV if (data->min_uV && data->max_uV
&& data->min_uV <= data->max_uV) { && data->min_uV <= data->max_uV) {
dev_dbg(dev, "Requesting %d-%duV\n",
data->min_uV, data->max_uV);
ret = regulator_set_voltage(data->regulator, ret = regulator_set_voltage(data->regulator,
data->min_uV, data->max_uV); data->min_uV, data->max_uV);
if (ret != 0) { if (ret != 0) {
printk(KERN_ERR "regulator_set_voltage() failed: %d\n", dev_err(dev,
ret); "regulator_set_voltage() failed: %d\n", ret);
return; return;
} }
} }
if (data->min_uV && data->max_uV && !data->enabled) { if (data->min_uV && data->max_uV && !data->enabled) {
dev_dbg(dev, "Enabling regulator\n");
ret = regulator_enable(data->regulator); ret = regulator_enable(data->regulator);
if (ret == 0) if (ret == 0)
data->enabled = 1; data->enabled = 1;
else else
printk(KERN_ERR "regulator_enable() failed: %d\n", dev_err(dev, "regulator_enable() failed: %d\n",
ret); ret);
} }
if (!(data->min_uV && data->max_uV) && data->enabled) { if (!(data->min_uV && data->max_uV) && data->enabled) {
dev_dbg(dev, "Disabling regulator\n");
ret = regulator_disable(data->regulator); ret = regulator_disable(data->regulator);
if (ret == 0) if (ret == 0)
data->enabled = 0; data->enabled = 0;
else else
printk(KERN_ERR "regulator_disable() failed: %d\n", dev_err(dev, "regulator_disable() failed: %d\n",
ret); ret);
} }
} }
static void update_current_limit_constraints(struct virtual_consumer_data static void update_current_limit_constraints(struct device *dev,
*data) struct virtual_consumer_data *data)
{ {
int ret; int ret;
if (data->max_uA if (data->max_uA
&& data->min_uA <= data->max_uA) { && data->min_uA <= data->max_uA) {
dev_dbg(dev, "Requesting %d-%duA\n",
data->min_uA, data->max_uA);
ret = regulator_set_current_limit(data->regulator, ret = regulator_set_current_limit(data->regulator,
data->min_uA, data->max_uA); data->min_uA, data->max_uA);
if (ret != 0) { if (ret != 0) {
pr_err("regulator_set_current_limit() failed: %d\n", dev_err(dev,
ret); "regulator_set_current_limit() failed: %d\n",
ret);
return; return;
} }
} }
if (data->max_uA && !data->enabled) { if (data->max_uA && !data->enabled) {
dev_dbg(dev, "Enabling regulator\n");
ret = regulator_enable(data->regulator); ret = regulator_enable(data->regulator);
if (ret == 0) if (ret == 0)
data->enabled = 1; data->enabled = 1;
else else
printk(KERN_ERR "regulator_enable() failed: %d\n", dev_err(dev, "regulator_enable() failed: %d\n",
ret); ret);
} }
if (!(data->min_uA && data->max_uA) && data->enabled) { if (!(data->min_uA && data->max_uA) && data->enabled) {
dev_dbg(dev, "Disabling regulator\n");
ret = regulator_disable(data->regulator); ret = regulator_disable(data->regulator);
if (ret == 0) if (ret == 0)
data->enabled = 0; data->enabled = 0;
else else
printk(KERN_ERR "regulator_disable() failed: %d\n", dev_err(dev, "regulator_disable() failed: %d\n",
ret); ret);
} }
} }
...@@ -115,7 +125,7 @@ static ssize_t set_min_uV(struct device *dev, struct device_attribute *attr, ...@@ -115,7 +125,7 @@ static ssize_t set_min_uV(struct device *dev, struct device_attribute *attr,
mutex_lock(&data->lock); mutex_lock(&data->lock);
data->min_uV = val; data->min_uV = val;
update_voltage_constraints(data); update_voltage_constraints(dev, data);
mutex_unlock(&data->lock); mutex_unlock(&data->lock);
...@@ -141,7 +151,7 @@ static ssize_t set_max_uV(struct device *dev, struct device_attribute *attr, ...@@ -141,7 +151,7 @@ static ssize_t set_max_uV(struct device *dev, struct device_attribute *attr,
mutex_lock(&data->lock); mutex_lock(&data->lock);
data->max_uV = val; data->max_uV = val;
update_voltage_constraints(data); update_voltage_constraints(dev, data);
mutex_unlock(&data->lock); mutex_unlock(&data->lock);
...@@ -167,7 +177,7 @@ static ssize_t set_min_uA(struct device *dev, struct device_attribute *attr, ...@@ -167,7 +177,7 @@ static ssize_t set_min_uA(struct device *dev, struct device_attribute *attr,
mutex_lock(&data->lock); mutex_lock(&data->lock);
data->min_uA = val; data->min_uA = val;
update_current_limit_constraints(data); update_current_limit_constraints(dev, data);
mutex_unlock(&data->lock); mutex_unlock(&data->lock);
...@@ -193,7 +203,7 @@ static ssize_t set_max_uA(struct device *dev, struct device_attribute *attr, ...@@ -193,7 +203,7 @@ static ssize_t set_max_uA(struct device *dev, struct device_attribute *attr,
mutex_lock(&data->lock); mutex_lock(&data->lock);
data->max_uA = val; data->max_uA = val;
update_current_limit_constraints(data); update_current_limit_constraints(dev, data);
mutex_unlock(&data->lock); mutex_unlock(&data->lock);
...@@ -276,8 +286,7 @@ static int regulator_virtual_consumer_probe(struct platform_device *pdev) ...@@ -276,8 +286,7 @@ static int regulator_virtual_consumer_probe(struct platform_device *pdev)
drvdata = kzalloc(sizeof(struct virtual_consumer_data), GFP_KERNEL); drvdata = kzalloc(sizeof(struct virtual_consumer_data), GFP_KERNEL);
if (drvdata == NULL) { if (drvdata == NULL) {
ret = -ENOMEM; return -ENOMEM;
goto err;
} }
mutex_init(&drvdata->lock); mutex_init(&drvdata->lock);
...@@ -285,13 +294,18 @@ static int regulator_virtual_consumer_probe(struct platform_device *pdev) ...@@ -285,13 +294,18 @@ static int regulator_virtual_consumer_probe(struct platform_device *pdev)
drvdata->regulator = regulator_get(&pdev->dev, reg_id); drvdata->regulator = regulator_get(&pdev->dev, reg_id);
if (IS_ERR(drvdata->regulator)) { if (IS_ERR(drvdata->regulator)) {
ret = PTR_ERR(drvdata->regulator); ret = PTR_ERR(drvdata->regulator);
dev_err(&pdev->dev, "Failed to obtain supply '%s': %d\n",
reg_id, ret);
goto err; goto err;
} }
for (i = 0; i < ARRAY_SIZE(attributes); i++) { for (i = 0; i < ARRAY_SIZE(attributes); i++) {
ret = device_create_file(&pdev->dev, attributes[i]); ret = device_create_file(&pdev->dev, attributes[i]);
if (ret != 0) if (ret != 0) {
goto err; dev_err(&pdev->dev, "Failed to create attr %d: %d\n",
i, ret);
goto err_regulator;
}
} }
drvdata->mode = regulator_get_mode(drvdata->regulator); drvdata->mode = regulator_get_mode(drvdata->regulator);
...@@ -300,6 +314,8 @@ static int regulator_virtual_consumer_probe(struct platform_device *pdev) ...@@ -300,6 +314,8 @@ static int regulator_virtual_consumer_probe(struct platform_device *pdev)
return 0; return 0;
err_regulator:
regulator_put(drvdata->regulator);
err: err:
for (i = 0; i < ARRAY_SIZE(attributes); i++) for (i = 0; i < ARRAY_SIZE(attributes); i++)
device_remove_file(&pdev->dev, attributes[i]); device_remove_file(&pdev->dev, attributes[i]);
......
...@@ -1419,6 +1419,8 @@ int wm8350_register_regulator(struct wm8350 *wm8350, int reg, ...@@ -1419,6 +1419,8 @@ int wm8350_register_regulator(struct wm8350 *wm8350, int reg,
{ {
struct platform_device *pdev; struct platform_device *pdev;
int ret; int ret;
if (reg < 0 || reg >= NUM_WM8350_REGULATORS)
return -EINVAL;
if (wm8350->pmic.pdev[reg]) if (wm8350->pmic.pdev[reg])
return -EBUSY; return -EBUSY;
......
#ifndef __LINUX_PMIC_DA903X_H #ifndef __LINUX_PMIC_DA903X_H
#define __LINUX_PMIC_DA903X_H #define __LINUX_PMIC_DA903X_H
/* Unified sub device IDs for DA9030/DA9034 */ /* Unified sub device IDs for DA9030/DA9034/DA9035 */
enum { enum {
DA9030_ID_LED_1, DA9030_ID_LED_1,
DA9030_ID_LED_2, DA9030_ID_LED_2,
...@@ -57,6 +57,8 @@ enum { ...@@ -57,6 +57,8 @@ enum {
DA9034_ID_LDO13, DA9034_ID_LDO13,
DA9034_ID_LDO14, DA9034_ID_LDO14,
DA9034_ID_LDO15, DA9034_ID_LDO15,
DA9035_ID_BUCK3,
}; };
/* /*
......
...@@ -125,6 +125,8 @@ struct regulator_bulk_data { ...@@ -125,6 +125,8 @@ struct regulator_bulk_data {
/* regulator get and put */ /* regulator get and put */
struct regulator *__must_check regulator_get(struct device *dev, struct regulator *__must_check regulator_get(struct device *dev,
const char *id); const char *id);
struct regulator *__must_check regulator_get_exclusive(struct device *dev,
const char *id);
void regulator_put(struct regulator *regulator); void regulator_put(struct regulator *regulator);
/* regulator output control and status */ /* regulator output control and status */
...@@ -144,6 +146,8 @@ void regulator_bulk_free(int num_consumers, ...@@ -144,6 +146,8 @@ void regulator_bulk_free(int num_consumers,
int regulator_count_voltages(struct regulator *regulator); int regulator_count_voltages(struct regulator *regulator);
int regulator_list_voltage(struct regulator *regulator, unsigned selector); int regulator_list_voltage(struct regulator *regulator, unsigned selector);
int regulator_is_supported_voltage(struct regulator *regulator,
int min_uV, int max_uV);
int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV); int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV);
int regulator_get_voltage(struct regulator *regulator); int regulator_get_voltage(struct regulator *regulator);
int regulator_set_current_limit(struct regulator *regulator, int regulator_set_current_limit(struct regulator *regulator,
......
...@@ -37,7 +37,8 @@ enum regulator_status { ...@@ -37,7 +37,8 @@ enum regulator_status {
* *
* @enable: Configure the regulator as enabled. * @enable: Configure the regulator as enabled.
* @disable: Configure the regulator as disabled. * @disable: Configure the regulator as disabled.
* @is_enabled: Return 1 if the regulator is enabled, 0 otherwise. * @is_enabled: Return 1 if the regulator is enabled, 0 if not.
* May also return negative errno.
* *
* @set_voltage: Set the voltage for the regulator within the range specified. * @set_voltage: Set the voltage for the regulator within the range specified.
* The driver should select the voltage closest to min_uV. * The driver should select the voltage closest to min_uV.
...@@ -162,6 +163,8 @@ struct regulator_desc { ...@@ -162,6 +163,8 @@ struct regulator_desc {
struct regulator_dev { struct regulator_dev {
struct regulator_desc *desc; struct regulator_desc *desc;
int use_count; int use_count;
int open_count;
int exclusive;
/* lists we belong to */ /* lists we belong to */
struct list_head list; /* list of all regulators */ struct list_head list; /* list of all regulators */
......
...@@ -5,6 +5,9 @@ ...@@ -5,6 +5,9 @@
* *
* Author: Mark Brown <broonie@opensource.wolfsonmicro.com> * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
* *
* Copyright (c) 2009 Nokia Corporation
* Roger Quadros <ext-roger.quadros@nokia.com>
*
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as * modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the * published by the Free Software Foundation; either version 2 of the
...@@ -16,9 +19,30 @@ ...@@ -16,9 +19,30 @@
struct regulator_init_data; struct regulator_init_data;
/**
* struct fixed_voltage_config - fixed_voltage_config structure
* @supply_name: Name of the regulator supply
* @microvolts: Output voltage of regulator
* @gpio: GPIO to use for enable control
* set to -EINVAL if not used
* @enable_high: Polarity of enable GPIO
* 1 = Active high, 0 = Active low
* @enabled_at_boot: Whether regulator has been enabled at
* boot or not. 1 = Yes, 0 = No
* This is used to keep the regulator at
* the default state
* @init_data: regulator_init_data
*
* This structure contains fixed voltage regulator configuration
* information that must be passed by platform code to the fixed
* voltage regulator driver.
*/
struct fixed_voltage_config { struct fixed_voltage_config {
const char *supply_name; const char *supply_name;
int microvolts; int microvolts;
int gpio;
unsigned enable_high:1;
unsigned enabled_at_boot:1;
struct regulator_init_data *init_data; struct regulator_init_data *init_data;
}; };
......
...@@ -41,7 +41,7 @@ struct regulator; ...@@ -41,7 +41,7 @@ struct regulator;
#define REGULATOR_CHANGE_DRMS 0x10 #define REGULATOR_CHANGE_DRMS 0x10
/** /**
* struct regulator_state - regulator state during low power syatem states * struct regulator_state - regulator state during low power system states
* *
* This describes a regulators state during a system wide low power state. * This describes a regulators state during a system wide low power state.
* *
...@@ -117,25 +117,37 @@ struct regulation_constraints { ...@@ -117,25 +117,37 @@ struct regulation_constraints {
/* mode to set on startup */ /* mode to set on startup */
unsigned int initial_mode; unsigned int initial_mode;
/* constriant flags */ /* constraint flags */
unsigned always_on:1; /* regulator never off when system is on */ unsigned always_on:1; /* regulator never off when system is on */
unsigned boot_on:1; /* bootloader/firmware enabled regulator */ unsigned boot_on:1; /* bootloader/firmware enabled regulator */
unsigned apply_uV:1; /* apply uV constraint iff min == max */ unsigned apply_uV:1; /* apply uV constraint if min == max */
}; };
/** /**
* struct regulator_consumer_supply - supply -> device mapping * struct regulator_consumer_supply - supply -> device mapping
* *
* This maps a supply name to a device. * This maps a supply name to a device. Only one of dev or dev_name
* can be specified. Use of dev_name allows support for buses which
* make struct device available late such as I2C and is the preferred
* form.
* *
* @dev: Device structure for the consumer. * @dev: Device structure for the consumer.
* @dev_name: Result of dev_name() for the consumer.
* @supply: Name for the supply. * @supply: Name for the supply.
*/ */
struct regulator_consumer_supply { struct regulator_consumer_supply {
struct device *dev; /* consumer */ struct device *dev; /* consumer */
const char *dev_name; /* dev_name() for consumer */
const char *supply; /* consumer supply - e.g. "vcc" */ const char *supply; /* consumer supply - e.g. "vcc" */
}; };
/* Initialize struct regulator_consumer_supply */
#define REGULATOR_SUPPLY(_name, _dev_name) \
{ \
.supply = _name, \
.dev_name = _dev_name, \
}
/** /**
* struct regulator_init_data - regulator platform initialisation data. * struct regulator_init_data - regulator platform initialisation data.
* *
...@@ -166,6 +178,12 @@ struct regulator_init_data { ...@@ -166,6 +178,12 @@ struct regulator_init_data {
int regulator_suspend_prepare(suspend_state_t state); int regulator_suspend_prepare(suspend_state_t state);
#ifdef CONFIG_REGULATOR
void regulator_has_full_constraints(void); void regulator_has_full_constraints(void);
#else
static inline void regulator_has_full_constraints(void)
{
}
#endif
#endif #endif
...@@ -36,7 +36,7 @@ ...@@ -36,7 +36,7 @@
* max1586_subdev_data - regulator data * max1586_subdev_data - regulator data
* @id: regulator Id (either MAX1586_V3 or MAX1586_V6) * @id: regulator Id (either MAX1586_V3 or MAX1586_V6)
* @name: regulator cute name (example for V3: "vcc_core") * @name: regulator cute name (example for V3: "vcc_core")
* @platform_data: regulator init data (contraints, supplies, ...) * @platform_data: regulator init data (constraints, supplies, ...)
*/ */
struct max1586_subdev_data { struct max1586_subdev_data {
int id; int id;
...@@ -46,7 +46,7 @@ struct max1586_subdev_data { ...@@ -46,7 +46,7 @@ struct max1586_subdev_data {
/** /**
* max1586_platform_data - platform data for max1586 * max1586_platform_data - platform data for max1586
* @num_subdevs: number of regultors used (may be 1 or 2) * @num_subdevs: number of regulators used (may be 1 or 2)
* @subdevs: regulator used * @subdevs: regulator used
* At most, there will be a regulator for V3 and one for V6 voltages. * At most, there will be a regulator for V3 and one for V6 voltages.
* @v3_gain: gain on the V3 voltage output multiplied by 1e6. * @v3_gain: gain on the V3 voltage output multiplied by 1e6.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment