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 ...
This commit is contained in:
commit
fd8b327ee4
22 changed files with 1982 additions and 192 deletions
33
Documentation/power/regulator/design.txt
Normal file
33
Documentation/power/regulator/design.txt
Normal file
|
@ -0,0 +1,33 @@
|
|||
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[] = {
|
|||
},
|
||||
};
|
||||
/* register regulator 1 device */
|
||||
platform_device_register(&wm8350_regulator_devices[0]);
|
||||
platform_device_register(®ulator_devices[0]);
|
||||
|
||||
/* register regulator 2 device */
|
||||
platform_device_register(&wm8350_regulator_devices[1]);
|
||||
platform_device_register(®ulator_devices[1]);
|
||||
|
|
|
@ -29,7 +29,7 @@ Some terms used in this document:-
|
|||
|
||||
|
||||
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.
|
||||
|
@ -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
|
||||
consumption and status.
|
||||
|
||||
See Documentation/ABI/testing/regulator-sysfs.txt
|
||||
See Documentation/ABI/testing/sysfs-class-regulator
|
||||
|
|
|
@ -10,8 +10,9 @@ Registration
|
|||
|
||||
Drivers can register a regulator by calling :-
|
||||
|
||||
struct regulator_dev *regulator_register(struct device *dev,
|
||||
struct regulator_desc *regulator_desc);
|
||||
struct regulator_dev *regulator_register(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
|
||||
core.
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
menuconfig REGULATOR
|
||||
bool "Voltage and Current Regulator Support"
|
||||
default n
|
||||
help
|
||||
Generic Voltage and Current Regulator support.
|
||||
|
||||
|
@ -30,7 +29,6 @@ config REGULATOR_DEBUG
|
|||
|
||||
config REGULATOR_FIXED_VOLTAGE
|
||||
tristate "Fixed voltage regulator support"
|
||||
default n
|
||||
help
|
||||
This driver provides support for fixed voltage regulators,
|
||||
useful for systems which use a combination of software
|
||||
|
@ -38,7 +36,6 @@ config REGULATOR_FIXED_VOLTAGE
|
|||
|
||||
config REGULATOR_VIRTUAL_CONSUMER
|
||||
tristate "Virtual regulator consumer support"
|
||||
default n
|
||||
help
|
||||
This driver provides a virtual consumer for the voltage and
|
||||
current regulator API which provides sysfs controls for
|
||||
|
@ -49,17 +46,15 @@ config REGULATOR_VIRTUAL_CONSUMER
|
|||
|
||||
config REGULATOR_USERSPACE_CONSUMER
|
||||
tristate "Userspace regulator consumer support"
|
||||
default n
|
||||
help
|
||||
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.
|
||||
|
||||
If unsure, say no.
|
||||
|
||||
config REGULATOR_BQ24022
|
||||
tristate "TI bq24022 Dual Input 1-Cell Li-Ion Charger IC"
|
||||
default n
|
||||
help
|
||||
This driver controls a TI bq24022 Charger attached via
|
||||
GPIOs. The provided current regulator can enable/disable
|
||||
|
@ -69,7 +64,6 @@ config REGULATOR_BQ24022
|
|||
config REGULATOR_MAX1586
|
||||
tristate "Maxim 1586/1587 voltage regulator"
|
||||
depends on I2C
|
||||
default n
|
||||
help
|
||||
This driver controls a Maxim 1586 or 1587 voltage output
|
||||
regulator via I2C bus. The provided regulator is suitable
|
||||
|
@ -147,5 +141,21 @@ config REGULATOR_AB3100
|
|||
AB3100 analog baseband dealing with power regulators
|
||||
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
|
||||
|
||||
|
|
|
@ -23,4 +23,7 @@ obj-$(CONFIG_REGULATOR_PCAP) += pcap-regulator.o
|
|||
obj-$(CONFIG_REGULATOR_MC13783) += mc13783.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
|
||||
|
|
|
@ -37,7 +37,7 @@ static int has_full_constraints;
|
|||
*/
|
||||
struct regulator_map {
|
||||
struct list_head list;
|
||||
struct device *dev;
|
||||
const char *dev_name; /* The dev_name() for the consumer */
|
||||
const char *supply;
|
||||
struct regulator_dev *regulator;
|
||||
};
|
||||
|
@ -232,7 +232,7 @@ static ssize_t regulator_name_show(struct device *dev,
|
|||
struct regulator_dev *rdev = dev_get_drvdata(dev);
|
||||
const char *name;
|
||||
|
||||
if (rdev->constraints->name)
|
||||
if (rdev->constraints && rdev->constraints->name)
|
||||
name = rdev->constraints->name;
|
||||
else if (rdev->desc->name)
|
||||
name = rdev->desc->name;
|
||||
|
@ -280,8 +280,13 @@ static ssize_t regulator_state_show(struct device *dev,
|
|||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct regulator_dev *rdev = dev_get_drvdata(dev);
|
||||
ssize_t ret;
|
||||
|
||||
return regulator_print_state(buf, _regulator_is_enabled(rdev));
|
||||
mutex_lock(&rdev->mutex);
|
||||
ret = regulator_print_state(buf, _regulator_is_enabled(rdev));
|
||||
mutex_unlock(&rdev->mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
static DEVICE_ATTR(state, 0444, regulator_state_show, NULL);
|
||||
|
||||
|
@ -857,23 +862,39 @@ out:
|
|||
* set_consumer_device_supply: Bind a regulator to a symbolic supply
|
||||
* @rdev: regulator source
|
||||
* @consumer_dev: device the supply applies to
|
||||
* @consumer_dev_name: dev_name() string for device supply applies to
|
||||
* @supply: symbolic name for supply
|
||||
*
|
||||
* Allows platform initialisation code to map physical regulator
|
||||
* sources to symbolic names for supplies for use by devices. Devices
|
||||
* should use these symbolic names to request regulators, avoiding the
|
||||
* 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,
|
||||
struct device *consumer_dev, const char *supply)
|
||||
struct device *consumer_dev, const char *consumer_dev_name,
|
||||
const char *supply)
|
||||
{
|
||||
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)
|
||||
return -EINVAL;
|
||||
|
||||
if (consumer_dev_name != NULL)
|
||||
has_dev = 1;
|
||||
else
|
||||
has_dev = 0;
|
||||
|
||||
list_for_each_entry(node, ®ulator_map_list, list) {
|
||||
if (consumer_dev != node->dev)
|
||||
if (consumer_dev_name != node->dev_name)
|
||||
continue;
|
||||
if (strcmp(node->supply, supply) != 0)
|
||||
continue;
|
||||
|
@ -886,30 +907,45 @@ static int set_consumer_device_supply(struct regulator_dev *rdev,
|
|||
return -EBUSY;
|
||||
}
|
||||
|
||||
node = kmalloc(sizeof(struct regulator_map), GFP_KERNEL);
|
||||
node = kzalloc(sizeof(struct regulator_map), GFP_KERNEL);
|
||||
if (node == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
node->regulator = rdev;
|
||||
node->dev = consumer_dev;
|
||||
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, ®ulator_map_list);
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if (consumer_dev && !consumer_dev_name)
|
||||
consumer_dev_name = dev_name(consumer_dev);
|
||||
|
||||
list_for_each_entry_safe(node, n, ®ulator_map_list, list) {
|
||||
if (rdev == node->regulator &&
|
||||
consumer_dev == node->dev) {
|
||||
list_del(&node->list);
|
||||
kfree(node);
|
||||
return;
|
||||
}
|
||||
if (rdev != node->regulator)
|
||||
continue;
|
||||
|
||||
if (consumer_dev_name && node->dev_name &&
|
||||
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)
|
|||
list_for_each_entry_safe(node, n, ®ulator_map_list, list) {
|
||||
if (rdev == node->regulator) {
|
||||
list_del(&node->list);
|
||||
kfree(node->dev_name);
|
||||
kfree(node);
|
||||
return;
|
||||
}
|
||||
|
@ -1001,6 +1038,77 @@ overflow_err:
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/* Internal regulator request function */
|
||||
static struct regulator *_regulator_get(struct device *dev, const char *id,
|
||||
int exclusive)
|
||||
{
|
||||
struct regulator_dev *rdev;
|
||||
struct regulator_map *map;
|
||||
struct regulator *regulator = ERR_PTR(-ENODEV);
|
||||
const char *devname = NULL;
|
||||
int ret;
|
||||
|
||||
if (id == NULL) {
|
||||
printk(KERN_ERR "regulator: get() with no identifier\n");
|
||||
return regulator;
|
||||
}
|
||||
|
||||
if (dev)
|
||||
devname = dev_name(dev);
|
||||
|
||||
mutex_lock(®ulator_list_mutex);
|
||||
|
||||
list_for_each_entry(map, ®ulator_map_list, list) {
|
||||
/* If the mapping has a device set up it must match */
|
||||
if (map->dev_name &&
|
||||
(!devname || strcmp(map->dev_name, devname)))
|
||||
continue;
|
||||
|
||||
if (strcmp(map->supply, id) == 0) {
|
||||
rdev = map->regulator;
|
||||
goto found;
|
||||
}
|
||||
}
|
||||
mutex_unlock(®ulator_list_mutex);
|
||||
return regulator;
|
||||
|
||||
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))
|
||||
goto out;
|
||||
|
||||
regulator = create_regulator(rdev, dev, id);
|
||||
if (regulator == NULL) {
|
||||
regulator = ERR_PTR(-ENOMEM);
|
||||
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:
|
||||
mutex_unlock(®ulator_list_mutex);
|
||||
|
||||
return regulator;
|
||||
}
|
||||
|
||||
/**
|
||||
* regulator_get - lookup and obtain a reference to a regulator.
|
||||
* @dev: device for regulator "consumer"
|
||||
|
@ -1016,43 +1124,37 @@ overflow_err:
|
|||
*/
|
||||
struct regulator *regulator_get(struct device *dev, const char *id)
|
||||
{
|
||||
struct regulator_dev *rdev;
|
||||
struct regulator_map *map;
|
||||
struct regulator *regulator = ERR_PTR(-ENODEV);
|
||||
|
||||
if (id == NULL) {
|
||||
printk(KERN_ERR "regulator: get() with no identifier\n");
|
||||
return regulator;
|
||||
}
|
||||
|
||||
mutex_lock(®ulator_list_mutex);
|
||||
|
||||
list_for_each_entry(map, ®ulator_map_list, list) {
|
||||
if (dev == map->dev &&
|
||||
strcmp(map->supply, id) == 0) {
|
||||
rdev = map->regulator;
|
||||
goto found;
|
||||
}
|
||||
}
|
||||
mutex_unlock(®ulator_list_mutex);
|
||||
return regulator;
|
||||
|
||||
found:
|
||||
if (!try_module_get(rdev->owner))
|
||||
goto out;
|
||||
|
||||
regulator = create_regulator(rdev, dev, id);
|
||||
if (regulator == NULL) {
|
||||
regulator = ERR_PTR(-ENOMEM);
|
||||
module_put(rdev->owner);
|
||||
}
|
||||
|
||||
out:
|
||||
mutex_unlock(®ulator_list_mutex);
|
||||
return regulator;
|
||||
return _regulator_get(dev, id, 0);
|
||||
}
|
||||
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: regulator source
|
||||
|
@ -1081,21 +1183,29 @@ void regulator_put(struct regulator *regulator)
|
|||
list_del(®ulator->list);
|
||||
kfree(regulator);
|
||||
|
||||
rdev->open_count--;
|
||||
rdev->exclusive = 0;
|
||||
|
||||
module_put(rdev->owner);
|
||||
mutex_unlock(®ulator_list_mutex);
|
||||
}
|
||||
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() */
|
||||
static int _regulator_enable(struct regulator_dev *rdev)
|
||||
{
|
||||
int ret = -EINVAL;
|
||||
|
||||
if (!rdev->constraints) {
|
||||
printk(KERN_ERR "%s: %s has no constraints\n",
|
||||
__func__, rdev->desc->name);
|
||||
return ret;
|
||||
}
|
||||
int ret;
|
||||
|
||||
/* do we need to enable the supply regulator first */
|
||||
if (rdev->supply) {
|
||||
|
@ -1108,24 +1218,35 @@ static int _regulator_enable(struct regulator_dev *rdev)
|
|||
}
|
||||
|
||||
/* check voltage and requested load before enabling */
|
||||
if (rdev->desc->ops->enable) {
|
||||
if (rdev->constraints &&
|
||||
(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_DRMS))
|
||||
drms_uA_update(rdev);
|
||||
|
||||
if (rdev->constraints &&
|
||||
(rdev->constraints->valid_ops_mask &
|
||||
REGULATOR_CHANGE_DRMS))
|
||||
drms_uA_update(rdev);
|
||||
if (rdev->use_count == 0) {
|
||||
/* The regulator may on if it's not switchable or left on */
|
||||
ret = _regulator_is_enabled(rdev);
|
||||
if (ret == -EINVAL || ret == 0) {
|
||||
if (!_regulator_can_change_status(rdev))
|
||||
return -EPERM;
|
||||
|
||||
ret = rdev->desc->ops->enable(rdev);
|
||||
if (ret < 0) {
|
||||
printk(KERN_ERR "%s: failed to enable %s: %d\n",
|
||||
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);
|
||||
return ret;
|
||||
}
|
||||
rdev->use_count++;
|
||||
return ret;
|
||||
/* Fallthrough on positive return values - already enabled */
|
||||
}
|
||||
|
||||
return ret;
|
||||
rdev->use_count++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1165,7 +1286,8 @@ static int _regulator_disable(struct regulator_dev *rdev)
|
|||
if (rdev->use_count == 1 && !rdev->constraints->always_on) {
|
||||
|
||||
/* 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);
|
||||
if (ret < 0) {
|
||||
printk(KERN_ERR "%s: failed to disable %s\n",
|
||||
|
@ -1265,20 +1387,11 @@ EXPORT_SYMBOL_GPL(regulator_force_disable);
|
|||
|
||||
static int _regulator_is_enabled(struct regulator_dev *rdev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&rdev->mutex);
|
||||
|
||||
/* sanity check */
|
||||
if (!rdev->desc->ops->is_enabled) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
if (!rdev->desc->ops->is_enabled)
|
||||
return -EINVAL;
|
||||
|
||||
ret = rdev->desc->ops->is_enabled(rdev);
|
||||
out:
|
||||
mutex_unlock(&rdev->mutex);
|
||||
return ret;
|
||||
return rdev->desc->ops->is_enabled(rdev);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1295,7 +1408,13 @@ out:
|
|||
*/
|
||||
int regulator_is_enabled(struct regulator *regulator)
|
||||
{
|
||||
return _regulator_is_enabled(regulator->rdev);
|
||||
int ret;
|
||||
|
||||
mutex_lock(®ulator->rdev->mutex);
|
||||
ret = _regulator_is_enabled(regulator->rdev);
|
||||
mutex_unlock(®ulator->rdev->mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(regulator_is_enabled);
|
||||
|
||||
|
@ -1349,6 +1468,35 @@ int regulator_list_voltage(struct regulator *regulator, unsigned selector)
|
|||
}
|
||||
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: regulator source
|
||||
|
@ -2091,11 +2239,13 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc,
|
|||
for (i = 0; i < init_data->num_consumer_supplies; i++) {
|
||||
ret = set_consumer_device_supply(rdev,
|
||||
init_data->consumer_supplies[i].dev,
|
||||
init_data->consumer_supplies[i].dev_name,
|
||||
init_data->consumer_supplies[i].supply);
|
||||
if (ret < 0) {
|
||||
for (--i; i >= 0; i--)
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -2130,6 +2280,7 @@ void regulator_unregister(struct regulator_dev *rdev)
|
|||
return;
|
||||
|
||||
mutex_lock(®ulator_list_mutex);
|
||||
WARN_ON(rdev->open_count);
|
||||
unset_regulator_supplies(rdev);
|
||||
list_del(&rdev->list);
|
||||
if (rdev->supply)
|
||||
|
@ -2277,14 +2428,14 @@ static int __init regulator_init_complete(void)
|
|||
ops = rdev->desc->ops;
|
||||
c = rdev->constraints;
|
||||
|
||||
if (c->name)
|
||||
if (c && c->name)
|
||||
name = c->name;
|
||||
else if (rdev->desc->name)
|
||||
name = rdev->desc->name;
|
||||
else
|
||||
name = "regulator";
|
||||
|
||||
if (!ops->disable || c->always_on)
|
||||
if (!ops->disable || (c && c->always_on))
|
||||
continue;
|
||||
|
||||
mutex_lock(&rdev->mutex);
|
||||
|
|
|
@ -64,6 +64,14 @@
|
|||
#define DA9034_MDTV2 (0x33)
|
||||
#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 regulator_desc desc;
|
||||
|
||||
|
@ -79,6 +87,10 @@ struct da903x_regulator_info {
|
|||
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)
|
||||
{
|
||||
return rdev_get_dev(rdev)->parent->parent;
|
||||
|
@ -162,6 +174,17 @@ static int da903x_is_enabled(struct regulator_dev *rdev)
|
|||
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 */
|
||||
static int da9030_set_ldo1_15_voltage(struct regulator_dev *rdev,
|
||||
int min_uV, int max_uV)
|
||||
|
@ -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 = (val > 7 || val < 20) ? 8 : val - 12;
|
||||
val = (val >= 20) ? val - 12 : ((val > 7) ? 8 : val);
|
||||
val <<= 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)
|
|||
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 = {
|
||||
.set_voltage = da903x_set_ldo_voltage,
|
||||
.get_voltage = da903x_get_voltage,
|
||||
.list_voltage = da903x_list_voltage,
|
||||
.enable = da903x_enable,
|
||||
.disable = da903x_disable,
|
||||
.is_enabled = da903x_is_enabled,
|
||||
|
@ -317,6 +349,7 @@ static struct regulator_ops da903x_regulator_ldo_ops = {
|
|||
static struct regulator_ops da9030_regulator_ldo14_ops = {
|
||||
.set_voltage = da9030_set_ldo14_voltage,
|
||||
.get_voltage = da9030_get_ldo14_voltage,
|
||||
.list_voltage = da903x_list_voltage,
|
||||
.enable = da903x_enable,
|
||||
.disable = da903x_disable,
|
||||
.is_enabled = da903x_is_enabled,
|
||||
|
@ -326,6 +359,7 @@ static struct regulator_ops da9030_regulator_ldo14_ops = {
|
|||
static struct regulator_ops da9030_regulator_ldo1_15_ops = {
|
||||
.set_voltage = da9030_set_ldo1_15_voltage,
|
||||
.get_voltage = da903x_get_voltage,
|
||||
.list_voltage = da903x_list_voltage,
|
||||
.enable = da903x_enable,
|
||||
.disable = da903x_disable,
|
||||
.is_enabled = da903x_is_enabled,
|
||||
|
@ -334,6 +368,7 @@ static struct regulator_ops da9030_regulator_ldo1_15_ops = {
|
|||
static struct regulator_ops da9034_regulator_dvc_ops = {
|
||||
.set_voltage = da9034_set_dvc_voltage,
|
||||
.get_voltage = da903x_get_voltage,
|
||||
.list_voltage = da903x_list_voltage,
|
||||
.enable = da903x_enable,
|
||||
.disable = da903x_disable,
|
||||
.is_enabled = da903x_is_enabled,
|
||||
|
@ -343,6 +378,7 @@ static struct regulator_ops da9034_regulator_dvc_ops = {
|
|||
static struct regulator_ops da9034_regulator_ldo12_ops = {
|
||||
.set_voltage = da9034_set_ldo12_voltage,
|
||||
.get_voltage = da9034_get_ldo12_voltage,
|
||||
.list_voltage = da9034_list_ldo12_voltage,
|
||||
.enable = da903x_enable,
|
||||
.disable = da903x_disable,
|
||||
.is_enabled = da903x_is_enabled,
|
||||
|
@ -355,6 +391,7 @@ static struct regulator_ops da9034_regulator_ldo12_ops = {
|
|||
.ops = &da903x_regulator_ldo_ops, \
|
||||
.type = REGULATOR_VOLTAGE, \
|
||||
.id = _pmic##_ID_LDO##_id, \
|
||||
.n_voltages = (step) ? ((max - min) / step + 1) : 1, \
|
||||
.owner = THIS_MODULE, \
|
||||
}, \
|
||||
.min_uV = (min) * 1000, \
|
||||
|
@ -367,24 +404,25 @@ static struct regulator_ops da9034_regulator_ldo12_ops = {
|
|||
.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 = { \
|
||||
.name = #_id, \
|
||||
.ops = &da9034_regulator_dvc_ops, \
|
||||
.type = REGULATOR_VOLTAGE, \
|
||||
.id = DA9034_ID_##_id, \
|
||||
.id = _pmic##_ID_##_id, \
|
||||
.n_voltages = (step) ? ((max - min) / step + 1) : 1, \
|
||||
.owner = THIS_MODULE, \
|
||||
}, \
|
||||
.min_uV = (min) * 1000, \
|
||||
.max_uV = (max) * 1000, \
|
||||
.step_uV = (step) * 1000, \
|
||||
.vol_reg = DA9034_##vreg, \
|
||||
.vol_reg = _pmic##_##vreg, \
|
||||
.vol_shift = (0), \
|
||||
.vol_nbits = (nbits), \
|
||||
.update_reg = DA9034_##ureg, \
|
||||
.update_reg = _pmic##_##ureg, \
|
||||
.update_bit = (ubit), \
|
||||
.enable_reg = DA9034_##ereg, \
|
||||
.enable_reg = _pmic##_##ereg, \
|
||||
.enable_bit = (ebit), \
|
||||
}
|
||||
|
||||
|
@ -394,8 +432,22 @@ static struct regulator_ops da9034_regulator_ldo12_ops = {
|
|||
#define DA9030_LDO(_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[] = {
|
||||
/* 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( 2, 1800, 3200, 100, LDO23, 0, 4, RCTL12, 2),
|
||||
DA9030_LDO( 3, 1800, 3200, 100, LDO23, 4, 4, RCTL12, 3),
|
||||
|
@ -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 */
|
||||
|
||||
/* DA9034 */
|
||||
DA9034_DVC(BUCK1, 725, 1500, 25, ADTV1, 5, VCC1, 0, OVER1, 0),
|
||||
DA9034_DVC(BUCK2, 725, 1500, 25, CDTV1, 5, VCC1, 2, OVER1, 1),
|
||||
DA9034_DVC(LDO2, 725, 1500, 25, SDTV1, 5, VCC1, 4, OVER1, 2),
|
||||
DA9034_DVC(BUCK1, 725, 1500, 25, ADTV2, 5, VCC1, 0, OVER1, 0),
|
||||
DA9034_DVC(BUCK2, 725, 1500, 25, CDTV2, 5, VCC1, 2, OVER1, 1),
|
||||
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_LDO( 3, 1800, 3300, 100, LDO643, 0, 4, OVER3, 5),
|
||||
|
@ -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(15, 1800, 3300, 100, LDO1514, 4, 4, OVER3, 1),
|
||||
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)
|
||||
|
@ -462,8 +517,10 @@ static int __devinit da903x_regulator_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
/* 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.n_voltages = ARRAY_SIZE(da9034_ldo12_data);
|
||||
}
|
||||
|
||||
if (ri->desc.id == DA9030_ID_LDO14)
|
||||
ri->desc.ops = &da9030_regulator_ldo14_ops;
|
||||
|
|
|
@ -5,6 +5,9 @@
|
|||
*
|
||||
* 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
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
|
@ -20,20 +23,45 @@
|
|||
#include <linux/platform_device.h>
|
||||
#include <linux/regulator/driver.h>
|
||||
#include <linux/regulator/fixed.h>
|
||||
#include <linux/gpio.h>
|
||||
|
||||
struct fixed_voltage_data {
|
||||
struct regulator_desc desc;
|
||||
struct regulator_dev *dev;
|
||||
int microvolts;
|
||||
int gpio;
|
||||
unsigned enable_high:1;
|
||||
unsigned is_enabled:1;
|
||||
};
|
||||
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -58,6 +86,7 @@ static int fixed_voltage_list_voltage(struct regulator_dev *dev,
|
|||
static struct regulator_ops fixed_voltage_ops = {
|
||||
.is_enabled = fixed_voltage_is_enabled,
|
||||
.enable = fixed_voltage_enable,
|
||||
.disable = fixed_voltage_disable,
|
||||
.get_voltage = fixed_voltage_get_voltage,
|
||||
.list_voltage = fixed_voltage_list_voltage,
|
||||
};
|
||||
|
@ -70,12 +99,14 @@ static int regulator_fixed_voltage_probe(struct platform_device *pdev)
|
|||
|
||||
drvdata = kzalloc(sizeof(struct fixed_voltage_data), GFP_KERNEL);
|
||||
if (drvdata == NULL) {
|
||||
dev_err(&pdev->dev, "Failed to allocate device data\n");
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
drvdata->desc.name = kstrdup(config->supply_name, GFP_KERNEL);
|
||||
if (drvdata->desc.name == NULL) {
|
||||
dev_err(&pdev->dev, "Failed to allocate supply name\n");
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
|
@ -85,12 +116,62 @@ static int regulator_fixed_voltage_probe(struct platform_device *pdev)
|
|||
drvdata->desc.n_voltages = 1;
|
||||
|
||||
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,
|
||||
config->init_data, drvdata);
|
||||
if (IS_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);
|
||||
|
@ -100,6 +181,9 @@ static int regulator_fixed_voltage_probe(struct platform_device *pdev)
|
|||
|
||||
return 0;
|
||||
|
||||
err_gpio:
|
||||
if (gpio_is_valid(config->gpio))
|
||||
gpio_free(config->gpio);
|
||||
err_name:
|
||||
kfree(drvdata->desc.name);
|
||||
err:
|
||||
|
@ -115,6 +199,9 @@ static int regulator_fixed_voltage_remove(struct platform_device *pdev)
|
|||
kfree(drvdata->desc.name);
|
||||
kfree(drvdata);
|
||||
|
||||
if (gpio_is_valid(drvdata->gpio))
|
||||
gpio_free(drvdata->gpio);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -541,7 +541,7 @@ static struct i2c_driver lp3971_i2c_driver = {
|
|||
|
||||
static int __init lp3971_module_init(void)
|
||||
{
|
||||
int ret = -ENODEV;
|
||||
int ret;
|
||||
|
||||
ret = i2c_add_driver(&lp3971_i2c_driver);
|
||||
if (ret != 0)
|
||||
|
|
|
@ -24,11 +24,12 @@
|
|||
#include <linux/mfd/pcf50633/core.h>
|
||||
#include <linux/mfd/pcf50633/pmic.h>
|
||||
|
||||
#define PCF50633_REGULATOR(_name, _id) \
|
||||
#define PCF50633_REGULATOR(_name, _id, _n) \
|
||||
{ \
|
||||
.name = _name, \
|
||||
.id = _id, \
|
||||
.ops = &pcf50633_regulator_ops, \
|
||||
.n_voltages = _n, \
|
||||
.type = REGULATOR_VOLTAGE, \
|
||||
.owner = THIS_MODULE, \
|
||||
}
|
||||
|
@ -149,33 +150,20 @@ static int pcf50633_regulator_set_voltage(struct regulator_dev *rdev,
|
|||
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 regulator_id, millivolts, volt_bits;
|
||||
u8 regnr;
|
||||
int millivolts;
|
||||
|
||||
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);
|
||||
if (volt_bits < 0)
|
||||
return -1;
|
||||
|
||||
switch (regulator_id) {
|
||||
switch (id) {
|
||||
case PCF50633_REGULATOR_AUTO:
|
||||
millivolts = auto_voltage_value(volt_bits);
|
||||
millivolts = auto_voltage_value(bits);
|
||||
break;
|
||||
case PCF50633_REGULATOR_DOWN1:
|
||||
millivolts = down_voltage_value(volt_bits);
|
||||
millivolts = down_voltage_value(bits);
|
||||
break;
|
||||
case PCF50633_REGULATOR_DOWN2:
|
||||
millivolts = down_voltage_value(volt_bits);
|
||||
millivolts = down_voltage_value(bits);
|
||||
break;
|
||||
case PCF50633_REGULATOR_LDO1:
|
||||
case PCF50633_REGULATOR_LDO2:
|
||||
|
@ -184,7 +172,7 @@ static int pcf50633_regulator_get_voltage(struct regulator_dev *rdev)
|
|||
case PCF50633_REGULATOR_LDO5:
|
||||
case PCF50633_REGULATOR_LDO6:
|
||||
case PCF50633_REGULATOR_HCLDO:
|
||||
millivolts = ldo_voltage_value(volt_bits);
|
||||
millivolts = ldo_voltage_value(bits);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
|
@ -193,6 +181,49 @@ static int pcf50633_regulator_get_voltage(struct regulator_dev *rdev)
|
|||
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)
|
||||
{
|
||||
struct pcf50633 *pcf = rdev_get_drvdata(rdev);
|
||||
|
@ -246,6 +277,7 @@ static int pcf50633_regulator_is_enabled(struct regulator_dev *rdev)
|
|||
static struct regulator_ops pcf50633_regulator_ops = {
|
||||
.set_voltage = pcf50633_regulator_set_voltage,
|
||||
.get_voltage = pcf50633_regulator_get_voltage,
|
||||
.list_voltage = pcf50633_regulator_list_voltage,
|
||||
.enable = pcf50633_regulator_enable,
|
||||
.disable = pcf50633_regulator_disable,
|
||||
.is_enabled = pcf50633_regulator_is_enabled,
|
||||
|
@ -253,27 +285,27 @@ static struct regulator_ops pcf50633_regulator_ops = {
|
|||
|
||||
static struct regulator_desc regulators[] = {
|
||||
[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, 95),
|
||||
[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, 27),
|
||||
[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, 27),
|
||||
[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, 27),
|
||||
[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, 26),
|
||||
[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)
|
||||
|
|
632
drivers/regulator/tps65023-regulator.c
Normal file
632
drivers/regulator/tps65023-regulator.c
Normal file
|
@ -0,0 +1,632 @@
|
|||
/*
|
||||
* 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");
|
714
drivers/regulator/tps6507x-regulator.c
Normal file
714
drivers/regulator/tps6507x-regulator.c
Normal file
|
@ -0,0 +1,714 @@
|
|||
/*
|
||||
* 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,
|
|||
static DEVICE_ATTR(name, 0444, reg_show_name, NULL);
|
||||
static DEVICE_ATTR(state, 0644, reg_show_state, reg_set_state);
|
||||
|
||||
static struct device_attribute *attributes[] = {
|
||||
&dev_attr_name,
|
||||
&dev_attr_state,
|
||||
static struct attribute *attributes[] = {
|
||||
&dev_attr_name.attr,
|
||||
&dev_attr_state.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const struct attribute_group attr_group = {
|
||||
.attrs = attributes,
|
||||
};
|
||||
|
||||
static int regulator_userspace_consumer_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct regulator_userspace_consumer_data *pdata;
|
||||
struct userspace_consumer_data *drvdata;
|
||||
int ret, i;
|
||||
int ret;
|
||||
|
||||
pdata = pdev->dev.platform_data;
|
||||
if (!pdata)
|
||||
|
@ -125,31 +130,29 @@ static int regulator_userspace_consumer_probe(struct platform_device *pdev)
|
|||
goto err_alloc_supplies;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(attributes); i++) {
|
||||
ret = device_create_file(&pdev->dev, attributes[i]);
|
||||
if (ret != 0)
|
||||
goto err_create_attrs;
|
||||
}
|
||||
ret = sysfs_create_group(&pdev->dev.kobj, &attr_group);
|
||||
if (ret != 0)
|
||||
goto err_create_attrs;
|
||||
|
||||
if (pdata->init_on)
|
||||
if (pdata->init_on) {
|
||||
ret = regulator_bulk_enable(drvdata->num_supplies,
|
||||
drvdata->supplies);
|
||||
|
||||
drvdata->enabled = pdata->init_on;
|
||||
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Failed to set initial state: %d\n", ret);
|
||||
goto err_create_attrs;
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev,
|
||||
"Failed to set initial state: %d\n", ret);
|
||||
goto err_enable;
|
||||
}
|
||||
}
|
||||
|
||||
drvdata->enabled = pdata->init_on;
|
||||
platform_set_drvdata(pdev, drvdata);
|
||||
|
||||
return 0;
|
||||
|
||||
err_create_attrs:
|
||||
for (i = 0; i < ARRAY_SIZE(attributes); i++)
|
||||
device_remove_file(&pdev->dev, attributes[i]);
|
||||
err_enable:
|
||||
sysfs_remove_group(&pdev->dev.kobj, &attr_group);
|
||||
|
||||
err_create_attrs:
|
||||
regulator_bulk_free(drvdata->num_supplies, drvdata->supplies);
|
||||
|
||||
err_alloc_supplies:
|
||||
|
@ -160,10 +163,8 @@ err_alloc_supplies:
|
|||
static int regulator_userspace_consumer_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct userspace_consumer_data *data = platform_get_drvdata(pdev);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(attributes); i++)
|
||||
device_remove_file(&pdev->dev, attributes[i]);
|
||||
sysfs_remove_group(&pdev->dev.kobj, &attr_group);
|
||||
|
||||
if (data->enabled)
|
||||
regulator_bulk_disable(data->num_supplies, data->supplies);
|
||||
|
|
|
@ -27,71 +27,81 @@ struct virtual_consumer_data {
|
|||
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;
|
||||
|
||||
if (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,
|
||||
data->min_uV, data->max_uV);
|
||||
data->min_uV, data->max_uV);
|
||||
if (ret != 0) {
|
||||
printk(KERN_ERR "regulator_set_voltage() failed: %d\n",
|
||||
ret);
|
||||
dev_err(dev,
|
||||
"regulator_set_voltage() failed: %d\n", ret);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (data->min_uV && data->max_uV && !data->enabled) {
|
||||
dev_dbg(dev, "Enabling regulator\n");
|
||||
ret = regulator_enable(data->regulator);
|
||||
if (ret == 0)
|
||||
data->enabled = 1;
|
||||
else
|
||||
printk(KERN_ERR "regulator_enable() failed: %d\n",
|
||||
dev_err(dev, "regulator_enable() failed: %d\n",
|
||||
ret);
|
||||
}
|
||||
|
||||
if (!(data->min_uV && data->max_uV) && data->enabled) {
|
||||
dev_dbg(dev, "Disabling regulator\n");
|
||||
ret = regulator_disable(data->regulator);
|
||||
if (ret == 0)
|
||||
data->enabled = 0;
|
||||
else
|
||||
printk(KERN_ERR "regulator_disable() failed: %d\n",
|
||||
dev_err(dev, "regulator_disable() failed: %d\n",
|
||||
ret);
|
||||
}
|
||||
}
|
||||
|
||||
static void update_current_limit_constraints(struct virtual_consumer_data
|
||||
*data)
|
||||
static void update_current_limit_constraints(struct device *dev,
|
||||
struct virtual_consumer_data *data)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (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,
|
||||
data->min_uA, data->max_uA);
|
||||
if (ret != 0) {
|
||||
pr_err("regulator_set_current_limit() failed: %d\n",
|
||||
ret);
|
||||
dev_err(dev,
|
||||
"regulator_set_current_limit() failed: %d\n",
|
||||
ret);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (data->max_uA && !data->enabled) {
|
||||
dev_dbg(dev, "Enabling regulator\n");
|
||||
ret = regulator_enable(data->regulator);
|
||||
if (ret == 0)
|
||||
data->enabled = 1;
|
||||
else
|
||||
printk(KERN_ERR "regulator_enable() failed: %d\n",
|
||||
dev_err(dev, "regulator_enable() failed: %d\n",
|
||||
ret);
|
||||
}
|
||||
|
||||
if (!(data->min_uA && data->max_uA) && data->enabled) {
|
||||
dev_dbg(dev, "Disabling regulator\n");
|
||||
ret = regulator_disable(data->regulator);
|
||||
if (ret == 0)
|
||||
data->enabled = 0;
|
||||
else
|
||||
printk(KERN_ERR "regulator_disable() failed: %d\n",
|
||||
dev_err(dev, "regulator_disable() failed: %d\n",
|
||||
ret);
|
||||
}
|
||||
}
|
||||
|
@ -115,7 +125,7 @@ static ssize_t set_min_uV(struct device *dev, struct device_attribute *attr,
|
|||
mutex_lock(&data->lock);
|
||||
|
||||
data->min_uV = val;
|
||||
update_voltage_constraints(data);
|
||||
update_voltage_constraints(dev, data);
|
||||
|
||||
mutex_unlock(&data->lock);
|
||||
|
||||
|
@ -141,7 +151,7 @@ static ssize_t set_max_uV(struct device *dev, struct device_attribute *attr,
|
|||
mutex_lock(&data->lock);
|
||||
|
||||
data->max_uV = val;
|
||||
update_voltage_constraints(data);
|
||||
update_voltage_constraints(dev, data);
|
||||
|
||||
mutex_unlock(&data->lock);
|
||||
|
||||
|
@ -167,7 +177,7 @@ static ssize_t set_min_uA(struct device *dev, struct device_attribute *attr,
|
|||
mutex_lock(&data->lock);
|
||||
|
||||
data->min_uA = val;
|
||||
update_current_limit_constraints(data);
|
||||
update_current_limit_constraints(dev, data);
|
||||
|
||||
mutex_unlock(&data->lock);
|
||||
|
||||
|
@ -193,7 +203,7 @@ static ssize_t set_max_uA(struct device *dev, struct device_attribute *attr,
|
|||
mutex_lock(&data->lock);
|
||||
|
||||
data->max_uA = val;
|
||||
update_current_limit_constraints(data);
|
||||
update_current_limit_constraints(dev, data);
|
||||
|
||||
mutex_unlock(&data->lock);
|
||||
|
||||
|
@ -276,8 +286,7 @@ static int regulator_virtual_consumer_probe(struct platform_device *pdev)
|
|||
|
||||
drvdata = kzalloc(sizeof(struct virtual_consumer_data), GFP_KERNEL);
|
||||
if (drvdata == NULL) {
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
mutex_init(&drvdata->lock);
|
||||
|
@ -285,13 +294,18 @@ static int regulator_virtual_consumer_probe(struct platform_device *pdev)
|
|||
drvdata->regulator = regulator_get(&pdev->dev, reg_id);
|
||||
if (IS_ERR(drvdata->regulator)) {
|
||||
ret = PTR_ERR(drvdata->regulator);
|
||||
dev_err(&pdev->dev, "Failed to obtain supply '%s': %d\n",
|
||||
reg_id, ret);
|
||||
goto err;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(attributes); i++) {
|
||||
ret = device_create_file(&pdev->dev, attributes[i]);
|
||||
if (ret != 0)
|
||||
goto err;
|
||||
if (ret != 0) {
|
||||
dev_err(&pdev->dev, "Failed to create attr %d: %d\n",
|
||||
i, ret);
|
||||
goto err_regulator;
|
||||
}
|
||||
}
|
||||
|
||||
drvdata->mode = regulator_get_mode(drvdata->regulator);
|
||||
|
@ -300,6 +314,8 @@ static int regulator_virtual_consumer_probe(struct platform_device *pdev)
|
|||
|
||||
return 0;
|
||||
|
||||
err_regulator:
|
||||
regulator_put(drvdata->regulator);
|
||||
err:
|
||||
for (i = 0; i < ARRAY_SIZE(attributes); i++)
|
||||
device_remove_file(&pdev->dev, attributes[i]);
|
||||
|
|
|
@ -1419,6 +1419,8 @@ int wm8350_register_regulator(struct wm8350 *wm8350, int reg,
|
|||
{
|
||||
struct platform_device *pdev;
|
||||
int ret;
|
||||
if (reg < 0 || reg >= NUM_WM8350_REGULATORS)
|
||||
return -EINVAL;
|
||||
|
||||
if (wm8350->pmic.pdev[reg])
|
||||
return -EBUSY;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef __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 {
|
||||
DA9030_ID_LED_1,
|
||||
DA9030_ID_LED_2,
|
||||
|
@ -57,6 +57,8 @@ enum {
|
|||
DA9034_ID_LDO13,
|
||||
DA9034_ID_LDO14,
|
||||
DA9034_ID_LDO15,
|
||||
|
||||
DA9035_ID_BUCK3,
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
@ -125,6 +125,8 @@ struct regulator_bulk_data {
|
|||
/* regulator get and put */
|
||||
struct regulator *__must_check regulator_get(struct device *dev,
|
||||
const char *id);
|
||||
struct regulator *__must_check regulator_get_exclusive(struct device *dev,
|
||||
const char *id);
|
||||
void regulator_put(struct regulator *regulator);
|
||||
|
||||
/* regulator output control and status */
|
||||
|
@ -144,6 +146,8 @@ void regulator_bulk_free(int num_consumers,
|
|||
|
||||
int regulator_count_voltages(struct regulator *regulator);
|
||||
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_get_voltage(struct regulator *regulator);
|
||||
int regulator_set_current_limit(struct regulator *regulator,
|
||||
|
|
|
@ -37,7 +37,8 @@ enum regulator_status {
|
|||
*
|
||||
* @enable: Configure the regulator as enabled.
|
||||
* @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.
|
||||
* The driver should select the voltage closest to min_uV.
|
||||
|
@ -162,6 +163,8 @@ struct regulator_desc {
|
|||
struct regulator_dev {
|
||||
struct regulator_desc *desc;
|
||||
int use_count;
|
||||
int open_count;
|
||||
int exclusive;
|
||||
|
||||
/* lists we belong to */
|
||||
struct list_head list; /* list of all regulators */
|
||||
|
|
|
@ -5,6 +5,9 @@
|
|||
*
|
||||
* 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
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
|
@ -16,9 +19,30 @@
|
|||
|
||||
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 {
|
||||
const char *supply_name;
|
||||
int microvolts;
|
||||
int gpio;
|
||||
unsigned enable_high:1;
|
||||
unsigned enabled_at_boot:1;
|
||||
struct regulator_init_data *init_data;
|
||||
};
|
||||
|
||||
|
|
|
@ -41,7 +41,7 @@ struct regulator;
|
|||
#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.
|
||||
*
|
||||
|
@ -117,25 +117,37 @@ struct regulation_constraints {
|
|||
/* mode to set on startup */
|
||||
unsigned int initial_mode;
|
||||
|
||||
/* constriant flags */
|
||||
/* constraint flags */
|
||||
unsigned always_on:1; /* regulator never off when system is on */
|
||||
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
|
||||
*
|
||||
* 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_name: Result of dev_name() for the consumer.
|
||||
* @supply: Name for the supply.
|
||||
*/
|
||||
struct regulator_consumer_supply {
|
||||
struct device *dev; /* consumer */
|
||||
const char *dev_name; /* dev_name() for consumer */
|
||||
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.
|
||||
*
|
||||
|
@ -166,6 +178,12 @@ struct regulator_init_data {
|
|||
|
||||
int regulator_suspend_prepare(suspend_state_t state);
|
||||
|
||||
#ifdef CONFIG_REGULATOR
|
||||
void regulator_has_full_constraints(void);
|
||||
#else
|
||||
static inline void regulator_has_full_constraints(void)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
@ -36,7 +36,7 @@
|
|||
* max1586_subdev_data - regulator data
|
||||
* @id: regulator Id (either MAX1586_V3 or MAX1586_V6)
|
||||
* @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 {
|
||||
int id;
|
||||
|
@ -46,7 +46,7 @@ struct max1586_subdev_data {
|
|||
|
||||
/**
|
||||
* 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
|
||||
* 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.
|
||||
|
|
Loading…
Reference in a new issue