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: (32 commits)
  regulator: twl4030 VAUX3 supports 3.0V
  regulator: Support disabling of unused regulators by machines
  regulator: Don't increment use_count for boot_on regulators
  twl4030-regulator: expose VPLL2
  regulator: refcount fixes
  regulator: Don't warn if we failed to get a regulator
  regulator: Allow boot_on regulators to be disabled by clients
  regulator: Implement list_voltage for WM835x LDOs and DCDCs
  twl4030-regulator: list more VAUX4 voltages
  regulator: Don't warn on omitted voltage constraints
  regulator: Implement list_voltage() for WM8400 DCDCs and LDOs
  MMC: regulator utilities
  regulator: twl4030 voltage enumeration (v2)
  regulator: twl4030 regulators
  regulator: get_status() grows kerneldoc
  regulator: enumerate voltages (v2)
  regulator: Fix get_mode() for WM835x DCDCs
  regulator: Allow regulators to set the initial operating mode
  regulator: Suggest use of datasheet supply or pin names for consumers
  regulator: email - update email address and regulator webpage.
  ...
This commit is contained in:
Linus Torvalds 2009-04-03 10:39:20 -07:00
commit 18b34b9546
22 changed files with 1220 additions and 117 deletions

View File

@ -4,8 +4,8 @@ KernelVersion: 2.6.26
Contact: Liam Girdwood <lrg@slimlogic.co.uk>
Description:
Some regulator directories will contain a field called
state. This reports the regulator enable status, for
regulators which can report that value.
state. This reports the regulator enable control, for
regulators which can report that input value.
This will be one of the following strings:
@ -14,16 +14,54 @@ Description:
'unknown'
'enabled' means the regulator output is ON and is supplying
power to the system.
power to the system (assuming no error prevents it).
'disabled' means the regulator output is OFF and is not
supplying power to the system..
supplying power to the system (unless some non-Linux
control has enabled it).
'unknown' means software cannot determine the state, or
the reported state is invalid.
NOTE: this field can be used in conjunction with microvolts
and microamps to determine regulator output levels.
or microamps to determine configured regulator output levels.
What: /sys/class/regulator/.../status
Description:
Some regulator directories will contain a field called
"status". This reports the current regulator status, for
regulators which can report that output value.
This will be one of the following strings:
off
on
error
fast
normal
idle
standby
"off" means the regulator is not supplying power to the
system.
"on" means the regulator is supplying power to the system,
and the regulator can't report a detailed operation mode.
"error" indicates an out-of-regulation status such as being
disabled due to thermal shutdown, or voltage being unstable
because of problems with the input power supply.
"fast", "normal", "idle", and "standby" are all detailed
regulator operation modes (described elsewhere). They
imply "on", but provide more detail.
Note that regulator status is a function of many inputs,
not limited to control inputs from Linux. For example,
the actual load presented may trigger "error" status; or
a regulator may be enabled by another user, even though
Linux did not enable it.
What: /sys/class/regulator/.../type
@ -58,7 +96,7 @@ Description:
Some regulator directories will contain a field called
microvolts. This holds the regulator output voltage setting
measured in microvolts (i.e. E-6 Volts), for regulators
which can report that voltage.
which can report the control input for voltage.
NOTE: This value should not be used to determine the regulator
output voltage level as this value is the same regardless of
@ -73,7 +111,7 @@ Description:
Some regulator directories will contain a field called
microamps. This holds the regulator output current limit
setting measured in microamps (i.e. E-6 Amps), for regulators
which can report that current.
which can report the control input for a current limit.
NOTE: This value should not be used to determine the regulator
output current level as this value is the same regardless of
@ -87,7 +125,7 @@ Contact: Liam Girdwood <lrg@slimlogic.co.uk>
Description:
Some regulator directories will contain a field called
opmode. This holds the current regulator operating mode,
for regulators which can report it.
for regulators which can report that control input value.
The opmode value can be one of the following strings:
@ -101,7 +139,8 @@ Description:
NOTE: This value should not be used to determine the regulator
output operating mode as this value is the same regardless of
whether the regulator is enabled or disabled.
whether the regulator is enabled or disabled. A "status"
attribute may be available to determine the actual mode.
What: /sys/class/regulator/.../min_microvolts

View File

@ -4847,7 +4847,7 @@ M: lrg@slimlogic.co.uk
P: Mark Brown
M: broonie@opensource.wolfsonmicro.com
W: http://opensource.wolfsonmicro.com/node/15
W: http://www.slimlogic.co.uk/?page_id=5
W: http://www.slimlogic.co.uk/?p=48
T: git kernel.org/pub/scm/linux/kernel/git/lrg/voltage-2.6.git
S: Supported

View File

@ -592,11 +592,9 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
/* maybe add LDOs that are omitted on cost-reduced parts */
if (twl_has_regulator() && !(features & TPS_SUBSET)) {
/*
child = add_regulator(TWL4030_REG_VPLL2, pdata->vpll2);
if (IS_ERR(child))
return PTR_ERR(child);
*/
child = add_regulator(TWL4030_REG_VMMC2, pdata->vmmc2);
if (IS_ERR(child))

View File

@ -21,6 +21,7 @@
#include <linux/leds.h>
#include <linux/scatterlist.h>
#include <linux/log2.h>
#include <linux/regulator/consumer.h>
#include <linux/mmc/card.h>
#include <linux/mmc/host.h>
@ -523,6 +524,105 @@ u32 mmc_vddrange_to_ocrmask(int vdd_min, int vdd_max)
}
EXPORT_SYMBOL(mmc_vddrange_to_ocrmask);
#ifdef CONFIG_REGULATOR
/**
* mmc_regulator_get_ocrmask - return mask of supported voltages
* @supply: regulator to use
*
* This returns either a negative errno, or a mask of voltages that
* can be provided to MMC/SD/SDIO devices using the specified voltage
* regulator. This would normally be called before registering the
* MMC host adapter.
*/
int mmc_regulator_get_ocrmask(struct regulator *supply)
{
int result = 0;
int count;
int i;
count = regulator_count_voltages(supply);
if (count < 0)
return count;
for (i = 0; i < count; i++) {
int vdd_uV;
int vdd_mV;
vdd_uV = regulator_list_voltage(supply, i);
if (vdd_uV <= 0)
continue;
vdd_mV = vdd_uV / 1000;
result |= mmc_vddrange_to_ocrmask(vdd_mV, vdd_mV);
}
return result;
}
EXPORT_SYMBOL(mmc_regulator_get_ocrmask);
/**
* mmc_regulator_set_ocr - set regulator to match host->ios voltage
* @vdd_bit: zero for power off, else a bit number (host->ios.vdd)
* @supply: regulator to use
*
* Returns zero on success, else negative errno.
*
* MMC host drivers may use this to enable or disable a regulator using
* a particular supply voltage. This would normally be called from the
* set_ios() method.
*/
int mmc_regulator_set_ocr(struct regulator *supply, unsigned short vdd_bit)
{
int result = 0;
int min_uV, max_uV;
int enabled;
enabled = regulator_is_enabled(supply);
if (enabled < 0)
return enabled;
if (vdd_bit) {
int tmp;
int voltage;
/* REVISIT mmc_vddrange_to_ocrmask() may have set some
* bits this regulator doesn't quite support ... don't
* be too picky, most cards and regulators are OK with
* a 0.1V range goof (it's a small error percentage).
*/
tmp = vdd_bit - ilog2(MMC_VDD_165_195);
if (tmp == 0) {
min_uV = 1650 * 1000;
max_uV = 1950 * 1000;
} else {
min_uV = 1900 * 1000 + tmp * 100 * 1000;
max_uV = min_uV + 100 * 1000;
}
/* avoid needless changes to this voltage; the regulator
* might not allow this operation
*/
voltage = regulator_get_voltage(supply);
if (voltage < 0)
result = voltage;
else if (voltage < min_uV || voltage > max_uV)
result = regulator_set_voltage(supply, min_uV, max_uV);
else
result = 0;
if (result == 0 && !enabled)
result = regulator_enable(supply);
} else if (enabled) {
result = regulator_disable(supply);
}
return result;
}
EXPORT_SYMBOL(mmc_regulator_set_ocr);
#endif
/*
* Mask off any voltages we don't support and select
* the lowest voltage

View File

@ -29,8 +29,12 @@ config REGULATOR_DEBUG
Say yes here to enable debugging support.
config REGULATOR_FIXED_VOLTAGE
tristate
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
managed regulators and simple non-configurable regulators.
config REGULATOR_VIRTUAL_CONSUMER
tristate "Virtual regulator consumer support"
@ -52,6 +56,13 @@ config REGULATOR_BQ24022
charging select between 100 mA and 500 mA charging current
limit.
config REGULATOR_TWL4030
bool "TI TWL4030/TWL5030/TPS695x0 PMIC"
depends on TWL4030_CORE
help
This driver supports the voltage regulators provided by
this family of companion chips.
config REGULATOR_WM8350
tristate "Wolfson Microelectroncis WM8350 AudioPlus PMIC"
depends on MFD_WM8350

View File

@ -8,6 +8,7 @@ obj-$(CONFIG_REGULATOR_FIXED_VOLTAGE) += fixed.o
obj-$(CONFIG_REGULATOR_VIRTUAL_CONSUMER) += virtual.o
obj-$(CONFIG_REGULATOR_BQ24022) += bq24022.o
obj-$(CONFIG_REGULATOR_TWL4030) += twl4030-regulator.o
obj-$(CONFIG_REGULATOR_WM8350) += wm8350-regulator.o
obj-$(CONFIG_REGULATOR_WM8400) += wm8400-regulator.o
obj-$(CONFIG_REGULATOR_DA903X) += da903x.o

View File

@ -105,7 +105,8 @@ static int __init bq24022_probe(struct platform_device *pdev)
ret = gpio_direction_output(pdata->gpio_iset2, 0);
ret = gpio_direction_output(pdata->gpio_nce, 1);
bq24022 = regulator_register(&bq24022_desc, &pdev->dev, pdata);
bq24022 = regulator_register(&bq24022_desc, &pdev->dev,
pdata->init_data, pdata);
if (IS_ERR(bq24022)) {
dev_dbg(&pdev->dev, "couldn't register regulator\n");
ret = PTR_ERR(bq24022);

View File

@ -28,33 +28,7 @@
static DEFINE_MUTEX(regulator_list_mutex);
static LIST_HEAD(regulator_list);
static LIST_HEAD(regulator_map_list);
/*
* struct regulator_dev
*
* Voltage / Current regulator class device. One for each regulator.
*/
struct regulator_dev {
struct regulator_desc *desc;
int use_count;
/* lists we belong to */
struct list_head list; /* list of all regulators */
struct list_head slist; /* list of supplied regulators */
/* lists we own */
struct list_head consumer_list; /* consumers we supply */
struct list_head supply_list; /* regulators we supply */
struct blocking_notifier_head notifier;
struct mutex mutex; /* consumer lock */
struct module *owner;
struct device dev;
struct regulation_constraints *constraints;
struct regulator_dev *supply; /* for tree */
void *reg_data; /* regulator_dev data */
};
static int has_full_constraints;
/*
* struct regulator_map
@ -79,7 +53,6 @@ struct regulator {
int uA_load;
int min_uV;
int max_uV;
int enabled; /* count of client enables */
char *supply_name;
struct device_attribute dev_attr;
struct regulator_dev *rdev;
@ -312,6 +285,47 @@ static ssize_t regulator_state_show(struct device *dev,
}
static DEVICE_ATTR(state, 0444, regulator_state_show, NULL);
static ssize_t regulator_status_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct regulator_dev *rdev = dev_get_drvdata(dev);
int status;
char *label;
status = rdev->desc->ops->get_status(rdev);
if (status < 0)
return status;
switch (status) {
case REGULATOR_STATUS_OFF:
label = "off";
break;
case REGULATOR_STATUS_ON:
label = "on";
break;
case REGULATOR_STATUS_ERROR:
label = "error";
break;
case REGULATOR_STATUS_FAST:
label = "fast";
break;
case REGULATOR_STATUS_NORMAL:
label = "normal";
break;
case REGULATOR_STATUS_IDLE:
label = "idle";
break;
case REGULATOR_STATUS_STANDBY:
label = "standby";
break;
default:
return -ERANGE;
}
return sprintf(buf, "%s\n", label);
}
static DEVICE_ATTR(status, 0444, regulator_status_show, NULL);
static ssize_t regulator_min_uA_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@ -678,6 +692,73 @@ static int set_machine_constraints(struct regulator_dev *rdev,
else
name = "regulator";
/* constrain machine-level voltage specs to fit
* the actual range supported by this regulator.
*/
if (ops->list_voltage && rdev->desc->n_voltages) {
int count = rdev->desc->n_voltages;
int i;
int min_uV = INT_MAX;
int max_uV = INT_MIN;
int cmin = constraints->min_uV;
int cmax = constraints->max_uV;
/* it's safe to autoconfigure fixed-voltage supplies */
if (count == 1 && !cmin) {
cmin = INT_MIN;
cmax = INT_MAX;
}
/* voltage constraints are optional */
if ((cmin == 0) && (cmax == 0))
goto out;
/* else require explicit machine-level constraints */
if (cmin <= 0 || cmax <= 0 || cmax < cmin) {
pr_err("%s: %s '%s' voltage constraints\n",
__func__, "invalid", name);
ret = -EINVAL;
goto out;
}
/* initial: [cmin..cmax] valid, [min_uV..max_uV] not */
for (i = 0; i < count; i++) {
int value;
value = ops->list_voltage(rdev, i);
if (value <= 0)
continue;
/* maybe adjust [min_uV..max_uV] */
if (value >= cmin && value < min_uV)
min_uV = value;
if (value <= cmax && value > max_uV)
max_uV = value;
}
/* final: [min_uV..max_uV] valid iff constraints valid */
if (max_uV < min_uV) {
pr_err("%s: %s '%s' voltage constraints\n",
__func__, "unsupportable", name);
ret = -EINVAL;
goto out;
}
/* use regulator's subset of machine constraints */
if (constraints->min_uV < min_uV) {
pr_debug("%s: override '%s' %s, %d -> %d\n",
__func__, name, "min_uV",
constraints->min_uV, min_uV);
constraints->min_uV = min_uV;
}
if (constraints->max_uV > max_uV) {
pr_debug("%s: override '%s' %s, %d -> %d\n",
__func__, name, "max_uV",
constraints->max_uV, max_uV);
constraints->max_uV = max_uV;
}
}
rdev->constraints = constraints;
/* do we need to apply the constraint voltage */
@ -695,10 +776,6 @@ static int set_machine_constraints(struct regulator_dev *rdev,
}
}
/* are we enabled at boot time by firmware / bootloader */
if (rdev->constraints->boot_on)
rdev->use_count = 1;
/* do we need to setup our suspend state */
if (constraints->initial_state) {
ret = suspend_prepare(rdev, constraints->initial_state);
@ -710,11 +787,27 @@ static int set_machine_constraints(struct regulator_dev *rdev,
}
}
/* if always_on is set then turn the regulator on if it's not
* already on. */
if (constraints->always_on && ops->enable &&
((ops->is_enabled && !ops->is_enabled(rdev)) ||
(!ops->is_enabled && !constraints->boot_on))) {
if (constraints->initial_mode) {
if (!ops->set_mode) {
printk(KERN_ERR "%s: no set_mode operation for %s\n",
__func__, name);
ret = -EINVAL;
goto out;
}
ret = ops->set_mode(rdev, constraints->initial_mode);
if (ret < 0) {
printk(KERN_ERR
"%s: failed to set initial mode for %s: %d\n",
__func__, name, ret);
goto out;
}
}
/* If the constraints say the regulator should be on at this point
* and we have control then make sure it is enabled.
*/
if ((constraints->always_on || constraints->boot_on) && ops->enable) {
ret = ops->enable(rdev);
if (ret < 0) {
printk(KERN_ERR "%s: failed to enable %s\n",
@ -817,6 +910,19 @@ static void unset_consumer_device_supply(struct regulator_dev *rdev,
}
}
static void unset_regulator_supplies(struct regulator_dev *rdev)
{
struct regulator_map *node, *n;
list_for_each_entry_safe(node, n, &regulator_map_list, list) {
if (rdev == node->regulator) {
list_del(&node->list);
kfree(node);
return;
}
}
}
#define REG_STR_SIZE 32
static struct regulator *create_regulator(struct regulator_dev *rdev,
@ -898,9 +1004,12 @@ static struct regulator *create_regulator(struct regulator_dev *rdev,
* @id: Supply name or regulator ID.
*
* Returns a struct regulator corresponding to the regulator producer,
* or IS_ERR() condition containing errno. Use of supply names
* configured via regulator_set_device_supply() is strongly
* encouraged.
* or IS_ERR() condition containing errno.
*
* Use of supply names configured via regulator_set_device_supply() is
* strongly encouraged. It is recommended that the supply name used
* should match the name used for the supply and/or the relevant
* device pins in the datasheet.
*/
struct regulator *regulator_get(struct device *dev, const char *id)
{
@ -922,8 +1031,6 @@ struct regulator *regulator_get(struct device *dev, const char *id)
goto found;
}
}
printk(KERN_ERR "regulator: Unable to get requested regulator: %s\n",
id);
mutex_unlock(&regulator_list_mutex);
return regulator;
@ -961,10 +1068,6 @@ void regulator_put(struct regulator *regulator)
mutex_lock(&regulator_list_mutex);
rdev = regulator->rdev;
if (WARN(regulator->enabled, "Releasing supply %s while enabled\n",
regulator->supply_name))
_regulator_disable(rdev);
/* remove any sysfs entries */
if (regulator->dev) {
sysfs_remove_link(&rdev->dev.kobj, regulator->supply_name);
@ -1039,12 +1142,7 @@ int regulator_enable(struct regulator *regulator)
int ret = 0;
mutex_lock(&rdev->mutex);
if (regulator->enabled == 0)
ret = _regulator_enable(rdev);
else if (regulator->enabled < 0)
ret = -EIO;
if (ret == 0)
regulator->enabled++;
ret = _regulator_enable(rdev);
mutex_unlock(&rdev->mutex);
return ret;
}
@ -1055,6 +1153,11 @@ static int _regulator_disable(struct regulator_dev *rdev)
{
int ret = 0;
if (WARN(rdev->use_count <= 0,
"unbalanced disables for %s\n",
rdev->desc->name))
return -EIO;
/* are we the last user and permitted to disable ? */
if (rdev->use_count == 1 && !rdev->constraints->always_on) {
@ -1103,16 +1206,7 @@ int regulator_disable(struct regulator *regulator)
int ret = 0;
mutex_lock(&rdev->mutex);
if (regulator->enabled == 1) {
ret = _regulator_disable(rdev);
if (ret == 0)
regulator->uA_load = 0;
} else if (WARN(regulator->enabled <= 0,
"unbalanced disables for supply %s\n",
regulator->supply_name))
ret = -EIO;
if (ret == 0)
regulator->enabled--;
ret = _regulator_disable(rdev);
mutex_unlock(&rdev->mutex);
return ret;
}
@ -1159,7 +1253,6 @@ int regulator_force_disable(struct regulator *regulator)
int ret;
mutex_lock(&regulator->rdev->mutex);
regulator->enabled = 0;
regulator->uA_load = 0;
ret = _regulator_force_disable(regulator->rdev);
mutex_unlock(&regulator->rdev->mutex);
@ -1203,6 +1296,56 @@ int regulator_is_enabled(struct regulator *regulator)
}
EXPORT_SYMBOL_GPL(regulator_is_enabled);
/**
* regulator_count_voltages - count regulator_list_voltage() selectors
* @regulator: regulator source
*
* Returns number of selectors, or negative errno. Selectors are
* numbered starting at zero, and typically correspond to bitfields
* in hardware registers.
*/
int regulator_count_voltages(struct regulator *regulator)
{
struct regulator_dev *rdev = regulator->rdev;
return rdev->desc->n_voltages ? : -EINVAL;
}
EXPORT_SYMBOL_GPL(regulator_count_voltages);
/**
* regulator_list_voltage - enumerate supported voltages
* @regulator: regulator source
* @selector: identify voltage to list
* Context: can sleep
*
* Returns a voltage that can be passed to @regulator_set_voltage(),
* zero if this selector code can't be used on this sytem, or a
* negative errno.
*/
int regulator_list_voltage(struct regulator *regulator, unsigned selector)
{
struct regulator_dev *rdev = regulator->rdev;
struct regulator_ops *ops = rdev->desc->ops;
int ret;
if (!ops->list_voltage || selector >= rdev->desc->n_voltages)
return -EINVAL;
mutex_lock(&rdev->mutex);
ret = ops->list_voltage(rdev, selector);
mutex_unlock(&rdev->mutex);
if (ret > 0) {
if (ret < rdev->constraints->min_uV)
ret = 0;
else if (ret > rdev->constraints->max_uV)
ret = 0;
}
return ret;
}
EXPORT_SYMBOL_GPL(regulator_list_voltage);
/**
* regulator_set_voltage - set regulator output voltage
* @regulator: regulator source
@ -1243,6 +1386,7 @@ int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV)
ret = rdev->desc->ops->set_voltage(rdev, min_uV, max_uV);
out:
_notifier_call_chain(rdev, REGULATOR_EVENT_VOLTAGE_CHANGE, NULL);
mutex_unlock(&rdev->mutex);
return ret;
}
@ -1543,20 +1687,23 @@ int regulator_unregister_notifier(struct regulator *regulator,
}
EXPORT_SYMBOL_GPL(regulator_unregister_notifier);
/* notify regulator consumers and downstream regulator consumers */
/* notify regulator consumers and downstream regulator consumers.
* Note mutex must be held by caller.
*/
static void _notifier_call_chain(struct regulator_dev *rdev,
unsigned long event, void *data)
{
struct regulator_dev *_rdev;
/* call rdev chain first */
mutex_lock(&rdev->mutex);
blocking_notifier_call_chain(&rdev->notifier, event, NULL);
mutex_unlock(&rdev->mutex);
/* now notify regulator we supply */
list_for_each_entry(_rdev, &rdev->supply_list, slist)
_notifier_call_chain(_rdev, event, data);
list_for_each_entry(_rdev, &rdev->supply_list, slist) {
mutex_lock(&_rdev->mutex);
_notifier_call_chain(_rdev, event, data);
mutex_unlock(&_rdev->mutex);
}
}
/**
@ -1703,6 +1850,7 @@ EXPORT_SYMBOL_GPL(regulator_bulk_free);
*
* Called by regulator drivers to notify clients a regulator event has
* occurred. We also notify regulator clients downstream.
* Note lock must be held by caller.
*/
int regulator_notifier_call_chain(struct regulator_dev *rdev,
unsigned long event, void *data)
@ -1744,6 +1892,11 @@ static int add_regulator_attributes(struct regulator_dev *rdev)
if (status < 0)
return status;
}
if (ops->get_status) {
status = device_create_file(dev, &dev_attr_status);
if (status < 0)
return status;
}
/* some attributes are type-specific */
if (rdev->desc->type == REGULATOR_CURRENT) {
@ -1828,17 +1981,18 @@ static int add_regulator_attributes(struct regulator_dev *rdev)
* regulator_register - register regulator
* @regulator_desc: regulator to register
* @dev: struct device for the regulator
* @init_data: platform provided init data, passed through by driver
* @driver_data: private regulator data
*
* Called by regulator drivers to register a regulator.
* Returns 0 on success.
*/
struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc,
struct device *dev, void *driver_data)
struct device *dev, struct regulator_init_data *init_data,
void *driver_data)
{
static atomic_t regulator_no = ATOMIC_INIT(0);
struct regulator_dev *rdev;
struct regulator_init_data *init_data = dev->platform_data;
int ret, i;
if (regulator_desc == NULL)
@ -1945,6 +2099,7 @@ void regulator_unregister(struct regulator_dev *rdev)
return;
mutex_lock(&regulator_list_mutex);
unset_regulator_supplies(rdev);
list_del(&rdev->list);
if (rdev->supply)
sysfs_remove_link(&rdev->dev.kobj, "supply");
@ -1988,6 +2143,23 @@ int regulator_suspend_prepare(suspend_state_t state)
}
EXPORT_SYMBOL_GPL(regulator_suspend_prepare);
/**
* regulator_has_full_constraints - the system has fully specified constraints
*
* Calling this function will cause the regulator API to disable all
* regulators which have a zero use count and don't have an always_on
* constraint in a late_initcall.
*
* The intention is that this will become the default behaviour in a
* future kernel release so users are encouraged to use this facility
* now.
*/
void regulator_has_full_constraints(void)
{
has_full_constraints = 1;
}
EXPORT_SYMBOL_GPL(regulator_has_full_constraints);
/**
* rdev_get_drvdata - get rdev regulator driver data
* @rdev: regulator
@ -2055,3 +2227,77 @@ static int __init regulator_init(void)
/* init early to allow our consumers to complete system booting */
core_initcall(regulator_init);
static int __init regulator_init_complete(void)
{
struct regulator_dev *rdev;
struct regulator_ops *ops;
struct regulation_constraints *c;
int enabled, ret;
const char *name;
mutex_lock(&regulator_list_mutex);
/* If we have a full configuration then disable any regulators
* which are not in use or always_on. This will become the
* default behaviour in the future.
*/
list_for_each_entry(rdev, &regulator_list, list) {
ops = rdev->desc->ops;
c = rdev->constraints;
if (c->name)
name = c->name;
else if (rdev->desc->name)
name = rdev->desc->name;
else
name = "regulator";
if (!ops->disable || c->always_on)
continue;
mutex_lock(&rdev->mutex);
if (rdev->use_count)
goto unlock;
/* If we can't read the status assume it's on. */
if (ops->is_enabled)
enabled = ops->is_enabled(rdev);
else
enabled = 1;
if (!enabled)
goto unlock;
if (has_full_constraints) {
/* We log since this may kill the system if it
* goes wrong. */
printk(KERN_INFO "%s: disabling %s\n",
__func__, name);
ret = ops->disable(rdev);
if (ret != 0) {
printk(KERN_ERR
"%s: couldn't disable %s: %d\n",
__func__, name, ret);
}
} else {
/* The intention is that in future we will
* assume that full constraints are provided
* so warn even if we aren't going to do
* anything here.
*/
printk(KERN_WARNING
"%s: incomplete constraints, leaving %s on\n",
__func__, name);
}
unlock:
mutex_unlock(&rdev->mutex);
}
mutex_unlock(&regulator_list_mutex);
return 0;
}
late_initcall(regulator_init_complete);

View File

@ -471,7 +471,8 @@ static int __devinit da903x_regulator_probe(struct platform_device *pdev)
if (ri->desc.id == DA9030_ID_LDO1 || ri->desc.id == DA9030_ID_LDO15)
ri->desc.ops = &da9030_regulator_ldo1_15_ops;
rdev = regulator_register(&ri->desc, &pdev->dev, ri);
rdev = regulator_register(&ri->desc, &pdev->dev,
pdev->dev.platform_data, ri);
if (IS_ERR(rdev)) {
dev_err(&pdev->dev, "failed to register regulator %s\n",
ri->desc.name);

View File

@ -73,7 +73,8 @@ static int regulator_fixed_voltage_probe(struct platform_device *pdev)
drvdata->microvolts = config->microvolts;
drvdata->dev = regulator_register(&drvdata->desc, drvdata);
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;

View File

@ -284,7 +284,8 @@ static int __devinit pcf50633_regulator_probe(struct platform_device *pdev)
/* Already set by core driver */
pcf = platform_get_drvdata(pdev);
rdev = regulator_register(&regulators[pdev->id], &pdev->dev, pcf);
rdev = regulator_register(&regulators[pdev->id], &pdev->dev,
pdev->dev.platform_data, pcf);
if (IS_ERR(rdev))
return PTR_ERR(rdev);

View File

@ -0,0 +1,500 @@
/*
* twl4030-regulator.c -- support regulators in twl4030 family chips
*
* Copyright (C) 2008 David Brownell
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/err.h>
#include <linux/platform_device.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <linux/i2c/twl4030.h>
/*
* The TWL4030/TW5030/TPS659x0 family chips include power management, a
* USB OTG transceiver, an RTC, ADC, PWM, and lots more. Some versions
* include an audio codec, battery charger, and more voltage regulators.
* These chips are often used in OMAP-based systems.
*
* This driver implements software-based resource control for various
* voltage regulators. This is usually augmented with state machine
* based control.
*/
struct twlreg_info {
/* start of regulator's PM_RECEIVER control register bank */
u8 base;
/* twl4030 resource ID, for resource control state machine */
u8 id;
/* voltage in mV = table[VSEL]; table_len must be a power-of-two */
u8 table_len;
const u16 *table;
/* chip constraints on regulator behavior */
u16 min_mV;
/* used by regulator core */
struct regulator_desc desc;
};
/* LDO control registers ... offset is from the base of its register bank.
* The first three registers of all power resource banks help hardware to
* manage the various resource groups.
*/
#define VREG_GRP 0
#define VREG_TYPE 1
#define VREG_REMAP 2
#define VREG_DEDICATED 3 /* LDO control */
static inline int
twl4030reg_read(struct twlreg_info *info, unsigned offset)
{
u8 value;
int status;
status = twl4030_i2c_read_u8(TWL4030_MODULE_PM_RECEIVER,
&value, info->base + offset);
return (status < 0) ? status : value;
}
static inline int
twl4030reg_write(struct twlreg_info *info, unsigned offset, u8 value)
{
return twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
value, info->base + offset);
}
/*----------------------------------------------------------------------*/
/* generic power resource operations, which work on all regulators */
static int twl4030reg_grp(struct regulator_dev *rdev)
{
return twl4030reg_read(rdev_get_drvdata(rdev), VREG_GRP);
}
/*
* Enable/disable regulators by joining/leaving the P1 (processor) group.
* We assume nobody else is updating the DEV_GRP registers.
*/
#define P3_GRP BIT(7) /* "peripherals" */
#define P2_GRP BIT(6) /* secondary processor, modem, etc */
#define P1_GRP BIT(5) /* CPU/Linux */
static int twl4030reg_is_enabled(struct regulator_dev *rdev)
{
int state = twl4030reg_grp(rdev);
if (state < 0)
return state;
return (state & P1_GRP) != 0;
}
static int twl4030reg_enable(struct regulator_dev *rdev)
{
struct twlreg_info *info = rdev_get_drvdata(rdev);
int grp;
grp = twl4030reg_read(info, VREG_GRP);
if (grp < 0)
return grp;
grp |= P1_GRP;
return twl4030reg_write(info, VREG_GRP, grp);
}
static int twl4030reg_disable(struct regulator_dev *rdev)
{
struct twlreg_info *info = rdev_get_drvdata(rdev);
int grp;
grp = twl4030reg_read(info, VREG_GRP);
if (grp < 0)
return grp;
grp &= ~P1_GRP;
return twl4030reg_write(info, VREG_GRP, grp);
}
static int twl4030reg_get_status(struct regulator_dev *rdev)
{
int state = twl4030reg_grp(rdev);
if (state < 0)
return state;
state &= 0x0f;
/* assume state != WARM_RESET; we'd not be running... */
if (!state)
return REGULATOR_STATUS_OFF;
return (state & BIT(3))
? REGULATOR_STATUS_NORMAL
: REGULATOR_STATUS_STANDBY;
}
static int twl4030reg_set_mode(struct regulator_dev *rdev, unsigned mode)
{
struct twlreg_info *info = rdev_get_drvdata(rdev);
unsigned message;
int status;
/* We can only set the mode through state machine commands... */
switch (mode) {
case REGULATOR_MODE_NORMAL:
message = MSG_SINGULAR(DEV_GRP_P1, info->id, RES_STATE_ACTIVE);
break;
case REGULATOR_MODE_STANDBY:
message = MSG_SINGULAR(DEV_GRP_P1, info->id, RES_STATE_SLEEP);
break;
default:
return -EINVAL;
}
/* Ensure the resource is associated with some group */
status = twl4030reg_grp(rdev);
if (status < 0)
return status;
if (!(status & (P3_GRP | P2_GRP | P1_GRP)))
return -EACCES;
status = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER,
message >> 8, 0x15 /* PB_WORD_MSB */ );
if (status >= 0)
return status;
return twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER,
message, 0x16 /* PB_WORD_LSB */ );
}
/*----------------------------------------------------------------------*/
/*
* Support for adjustable-voltage LDOs uses a four bit (or less) voltage
* select field in its control register. We use tables indexed by VSEL
* to record voltages in milliVolts. (Accuracy is about three percent.)
*
* Note that VSEL values for VAUX2 changed in twl5030 and newer silicon;
* currently handled by listing two slightly different VAUX2 regulators,
* only one of which will be configured.
*
* VSEL values documented as "TI cannot support these values" are flagged
* in these tables as UNSUP() values; we normally won't assign them.
*
* VAUX3 at 3V is incorrectly listed in some TI manuals as unsupported.
* TI are revising the twl5030/tps659x0 specs to support that 3.0V setting.
*/
#ifdef CONFIG_TWL4030_ALLOW_UNSUPPORTED
#define UNSUP_MASK 0x0000
#else
#define UNSUP_MASK 0x8000
#endif
#define UNSUP(x) (UNSUP_MASK | (x))
#define IS_UNSUP(x) (UNSUP_MASK & (x))
#define LDO_MV(x) (~UNSUP_MASK & (x))
static const u16 VAUX1_VSEL_table[] = {
UNSUP(1500), UNSUP(1800), 2500, 2800,
3000, 3000, 3000, 3000,
};
static const u16 VAUX2_4030_VSEL_table[] = {
UNSUP(1000), UNSUP(1000), UNSUP(1200), 1300,
1500, 1800, UNSUP(1850), 2500,
UNSUP(2600), 2800, UNSUP(2850), UNSUP(3000),
UNSUP(3150), UNSUP(3150), UNSUP(3150), UNSUP(3150),
};
static const u16 VAUX2_VSEL_table[] = {
1700, 1700, 1900, 1300,
1500, 1800, 2000, 2500,
2100, 2800, 2200, 2300,
2400, 2400, 2400, 2400,
};
static const u16 VAUX3_VSEL_table[] = {
1500, 1800, 2500, 2800,
3000, 3000, 3000, 3000,
};
static const u16 VAUX4_VSEL_table[] = {
700, 1000, 1200, UNSUP(1300),
1500, 1800, UNSUP(1850), 2500,
UNSUP(2600), 2800, UNSUP(2850), UNSUP(3000),
UNSUP(3150), UNSUP(3150), UNSUP(3150), UNSUP(3150),
};
static const u16 VMMC1_VSEL_table[] = {
1850, 2850, 3000, 3150,
};
static const u16 VMMC2_VSEL_table[] = {
UNSUP(1000), UNSUP(1000), UNSUP(1200), UNSUP(1300),
UNSUP(1500), UNSUP(1800), 1850, UNSUP(2500),
2600, 2800, 2850, 3000,
3150, 3150, 3150, 3150,
};
static const u16 VPLL1_VSEL_table[] = {
1000, 1200, 1300, 1800,
UNSUP(2800), UNSUP(3000), UNSUP(3000), UNSUP(3000),
};
static const u16 VPLL2_VSEL_table[] = {
700, 1000, 1200, 1300,
UNSUP(1500), 1800, UNSUP(1850), UNSUP(2500),
UNSUP(2600), UNSUP(2800), UNSUP(2850), UNSUP(3000),
UNSUP(3150), UNSUP(3150), UNSUP(3150), UNSUP(3150),
};
static const u16 VSIM_VSEL_table[] = {
UNSUP(1000), UNSUP(1200), UNSUP(1300), 1800,
2800, 3000, 3000, 3000,
};
static const u16 VDAC_VSEL_table[] = {
1200, 1300, 1800, 1800,
};
static int twl4030ldo_list_voltage(struct regulator_dev *rdev, unsigned index)
{
struct twlreg_info *info = rdev_get_drvdata(rdev);
int mV = info->table[index];
return IS_UNSUP(mV) ? 0 : (LDO_MV(mV) * 1000);
}
static int
twl4030ldo_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV)
{
struct twlreg_info *info = rdev_get_drvdata(rdev);
int vsel;
for (vsel = 0; vsel < info->table_len; vsel++) {
int mV = info->table[vsel];
int uV;
if (IS_UNSUP(mV))
continue;
uV = LDO_MV(mV) * 1000;
/* REVISIT for VAUX2, first match may not be best/lowest */
/* use the first in-range value */
if (min_uV <= uV && uV <= max_uV)
return twl4030reg_write(info, VREG_DEDICATED, vsel);
}
return -EDOM;
}
static int twl4030ldo_get_voltage(struct regulator_dev *rdev)
{
struct twlreg_info *info = rdev_get_drvdata(rdev);
int vsel = twl4030reg_read(info, VREG_DEDICATED);
if (vsel < 0)
return vsel;
vsel &= info->table_len - 1;
return LDO_MV(info->table[vsel]) * 1000;
}
static struct regulator_ops twl4030ldo_ops = {
.list_voltage = twl4030ldo_list_voltage,
.set_voltage = twl4030ldo_set_voltage,
.get_voltage = twl4030ldo_get_voltage,
.enable = twl4030reg_enable,
.disable = twl4030reg_disable,
.is_enabled = twl4030reg_is_enabled,
.set_mode = twl4030reg_set_mode,
.get_status = twl4030reg_get_status,
};
/*----------------------------------------------------------------------*/
/*
* Fixed voltage LDOs don't have a VSEL field to update.
*/
static int twl4030fixed_list_voltage(struct regulator_dev *rdev, unsigned index)
{
struct twlreg_info *info = rdev_get_drvdata(rdev);
return info->min_mV * 1000;
}
static int twl4030fixed_get_voltage(struct regulator_dev *rdev)
{
struct twlreg_info *info = rdev_get_drvdata(rdev);
return info->min_mV * 1000;
}
static struct regulator_ops twl4030fixed_ops = {
.list_voltage = twl4030fixed_list_voltage,
.get_voltage = twl4030fixed_get_voltage,
.enable = twl4030reg_enable,
.disable = twl4030reg_disable,
.is_enabled = twl4030reg_is_enabled,
.set_mode = twl4030reg_set_mode,
.get_status = twl4030reg_get_status,
};
/*----------------------------------------------------------------------*/
#define TWL_ADJUSTABLE_LDO(label, offset, num) { \
.base = offset, \
.id = num, \
.table_len = ARRAY_SIZE(label##_VSEL_table), \
.table = label##_VSEL_table, \
.desc = { \
.name = #label, \
.id = TWL4030_REG_##label, \
.n_voltages = ARRAY_SIZE(label##_VSEL_table), \
.ops = &twl4030ldo_ops, \
.type = REGULATOR_VOLTAGE, \
.owner = THIS_MODULE, \
}, \
}
#define TWL_FIXED_LDO(label, offset, mVolts, num) { \
.base = offset, \
.id = num, \
.min_mV = mVolts, \
.desc = { \
.name = #label, \
.id = TWL4030_REG_##label, \
.n_voltages = 1, \
.ops = &twl4030fixed_ops, \
.type = REGULATOR_VOLTAGE, \
.owner = THIS_MODULE, \
}, \
}
/*
* We list regulators here if systems need some level of
* software control over them after boot.
*/
static struct twlreg_info twl4030_regs[] = {
TWL_ADJUSTABLE_LDO(VAUX1, 0x17, 1),
TWL_ADJUSTABLE_LDO(VAUX2_4030, 0x1b, 2),
TWL_ADJUSTABLE_LDO(VAUX2, 0x1b, 2),
TWL_ADJUSTABLE_LDO(VAUX3, 0x1f, 3),
TWL_ADJUSTABLE_LDO(VAUX4, 0x23, 4),
TWL_ADJUSTABLE_LDO(VMMC1, 0x27, 5),
TWL_ADJUSTABLE_LDO(VMMC2, 0x2b, 6),
/*
TWL_ADJUSTABLE_LDO(VPLL1, 0x2f, 7),
*/
TWL_ADJUSTABLE_LDO(VPLL2, 0x33, 8),
TWL_ADJUSTABLE_LDO(VSIM, 0x37, 9),
TWL_ADJUSTABLE_LDO(VDAC, 0x3b, 10),
/*
TWL_ADJUSTABLE_LDO(VINTANA1, 0x3f, 11),
TWL_ADJUSTABLE_LDO(VINTANA2, 0x43, 12),
TWL_ADJUSTABLE_LDO(VINTDIG, 0x47, 13),
TWL_SMPS(VIO, 0x4b, 14),
TWL_SMPS(VDD1, 0x55, 15),
TWL_SMPS(VDD2, 0x63, 16),
*/
TWL_FIXED_LDO(VUSB1V5, 0x71, 1500, 17),
TWL_FIXED_LDO(VUSB1V8, 0x74, 1800, 18),
TWL_FIXED_LDO(VUSB3V1, 0x77, 3100, 19),
/* VUSBCP is managed *only* by the USB subchip */
};
static int twl4030reg_probe(struct platform_device *pdev)
{
int i;
struct twlreg_info *info;
struct regulator_init_data *initdata;
struct regulation_constraints *c;
struct regulator_dev *rdev;
for (i = 0, info = NULL; i < ARRAY_SIZE(twl4030_regs); i++) {
if (twl4030_regs[i].desc.id != pdev->id)
continue;
info = twl4030_regs + i;
break;
}
if (!info)
return -ENODEV;
initdata = pdev->dev.platform_data;
if (!initdata)
return -EINVAL;
/* Constrain board-specific capabilities according to what
* this driver and the chip itself can actually do.
*/
c = &initdata->constraints;
c->valid_modes_mask &= REGULATOR_MODE_NORMAL | REGULATOR_MODE_STANDBY;
c->valid_ops_mask &= REGULATOR_CHANGE_VOLTAGE
| REGULATOR_CHANGE_MODE
| REGULATOR_CHANGE_STATUS;
rdev = regulator_register(&info->desc, &pdev->dev, initdata, info);
if (IS_ERR(rdev)) {
dev_err(&pdev->dev, "can't register %s, %ld\n",
info->desc.name, PTR_ERR(rdev));
return PTR_ERR(rdev);
}
platform_set_drvdata(pdev, rdev);
/* NOTE: many regulators support short-circuit IRQs (presentable
* as REGULATOR_OVER_CURRENT notifications?) configured via:
* - SC_CONFIG
* - SC_DETECT1 (vintana2, vmmc1/2, vaux1/2/3/4)
* - SC_DETECT2 (vusb, vdac, vio, vdd1/2, vpll2)
* - IT_CONFIG
*/
return 0;
}
static int __devexit twl4030reg_remove(struct platform_device *pdev)
{
regulator_unregister(platform_get_drvdata(pdev));
return 0;
}
MODULE_ALIAS("platform:twl4030_reg");
static struct platform_driver twl4030reg_driver = {
.probe = twl4030reg_probe,
.remove = __devexit_p(twl4030reg_remove),
/* NOTE: short name, to work around driver model truncation of
* "twl4030_regulator.12" (and friends) to "twl4030_regulator.1".
*/
.driver.name = "twl4030_reg",
.driver.owner = THIS_MODULE,
};
static int __init twl4030reg_init(void)
{
return platform_driver_register(&twl4030reg_driver);
}
subsys_initcall(twl4030reg_init);
static void __exit twl4030reg_exit(void)
{
platform_driver_unregister(&twl4030reg_driver);
}
module_exit(twl4030reg_exit)
MODULE_DESCRIPTION("TWL4030 regulator driver");
MODULE_LICENSE("GPL");

View File

@ -226,13 +226,17 @@ static ssize_t set_mode(struct device *dev, struct device_attribute *attr,
unsigned int mode;
int ret;
if (strncmp(buf, "fast", strlen("fast")) == 0)
/*
* sysfs_streq() doesn't need the \n's, but we add them so the strings
* will be shared with show_mode(), above.
*/
if (sysfs_streq(buf, "fast\n") == 0)
mode = REGULATOR_MODE_FAST;
else if (strncmp(buf, "normal", strlen("normal")) == 0)
else if (sysfs_streq(buf, "normal\n") == 0)
mode = REGULATOR_MODE_NORMAL;
else if (strncmp(buf, "idle", strlen("idle")) == 0)
else if (sysfs_streq(buf, "idle\n") == 0)
mode = REGULATOR_MODE_IDLE;
else if (strncmp(buf, "standby", strlen("standby")) == 0)
else if (sysfs_streq(buf, "standby\n") == 0)
mode = REGULATOR_MODE_STANDBY;
else {
dev_err(dev, "Configuring invalid mode\n");
@ -256,7 +260,7 @@ static DEVICE_ATTR(min_microamps, 0666, show_min_uA, set_min_uA);
static DEVICE_ATTR(max_microamps, 0666, show_max_uA, set_max_uA);
static DEVICE_ATTR(mode, 0666, show_mode, set_mode);
struct device_attribute *attributes[] = {
static struct device_attribute *attributes[] = {
&dev_attr_min_microvolts,
&dev_attr_max_microvolts,
&dev_attr_min_microamps,

View File

@ -24,6 +24,9 @@
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
/* Maximum value possible for VSEL */
#define WM8350_DCDC_MAX_VSEL 0x66
/* Microamps */
static const int isink_cur[] = {
4,
@ -385,6 +388,14 @@ static int wm8350_dcdc_get_voltage(struct regulator_dev *rdev)
return wm8350_dcdc_val_to_mvolts(val) * 1000;
}
static int wm8350_dcdc_list_voltage(struct regulator_dev *rdev,
unsigned selector)
{
if (selector > WM8350_DCDC_MAX_VSEL)
return -EINVAL;
return wm8350_dcdc_val_to_mvolts(selector) * 1000;
}
static int wm8350_dcdc_set_suspend_voltage(struct regulator_dev *rdev, int uV)
{
struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
@ -775,6 +786,14 @@ static int wm8350_ldo_get_voltage(struct regulator_dev *rdev)
return wm8350_ldo_val_to_mvolts(val) * 1000;
}
static int wm8350_ldo_list_voltage(struct regulator_dev *rdev,
unsigned selector)
{
if (selector > WM8350_LDO1_VSEL_MASK)
return -EINVAL;
return wm8350_ldo_val_to_mvolts(selector) * 1000;
}
int wm8350_dcdc_set_slot(struct wm8350 *wm8350, int dcdc, u16 start,
u16 stop, u16 fault)
{
@ -1031,18 +1050,30 @@ static unsigned int wm8350_dcdc_get_mode(struct regulator_dev *rdev)
int dcdc = rdev_get_id(rdev);
u16 mask, sleep, active, force;
int mode = REGULATOR_MODE_NORMAL;
int reg;
if (dcdc < WM8350_DCDC_1 || dcdc > WM8350_DCDC_6)
return -EINVAL;
if (dcdc == WM8350_DCDC_2 || dcdc == WM8350_DCDC_5)
switch (dcdc) {
case WM8350_DCDC_1:
reg = WM8350_DCDC1_FORCE_PWM;
break;
case WM8350_DCDC_3:
reg = WM8350_DCDC3_FORCE_PWM;
break;
case WM8350_DCDC_4:
reg = WM8350_DCDC4_FORCE_PWM;
break;
case WM8350_DCDC_6:
reg = WM8350_DCDC6_FORCE_PWM;
break;
default:
return -EINVAL;
}
mask = 1 << (dcdc - WM8350_DCDC_1);
active = wm8350_reg_read(wm8350, WM8350_DCDC_ACTIVE_OPTIONS) & mask;
force = wm8350_reg_read(wm8350, reg) & WM8350_DCDC1_FORCE_PWM_ENA;
sleep = wm8350_reg_read(wm8350, WM8350_DCDC_SLEEP_OPTIONS) & mask;
force = wm8350_reg_read(wm8350, WM8350_DCDC1_FORCE_PWM)
& WM8350_DCDC1_FORCE_PWM_ENA;
dev_dbg(wm8350->dev, "mask %x active %x sleep %x force %x",
mask, active, sleep, force);
@ -1150,6 +1181,7 @@ static int wm8350_ldo_is_enabled(struct regulator_dev *rdev)
static struct regulator_ops wm8350_dcdc_ops = {
.set_voltage = wm8350_dcdc_set_voltage,
.get_voltage = wm8350_dcdc_get_voltage,
.list_voltage = wm8350_dcdc_list_voltage,
.enable = wm8350_dcdc_enable,
.disable = wm8350_dcdc_disable,
.get_mode = wm8350_dcdc_get_mode,
@ -1173,6 +1205,7 @@ static struct regulator_ops wm8350_dcdc2_5_ops = {
static struct regulator_ops wm8350_ldo_ops = {
.set_voltage = wm8350_ldo_set_voltage,
.get_voltage = wm8350_ldo_get_voltage,
.list_voltage = wm8350_ldo_list_voltage,
.enable = wm8350_ldo_enable,
.disable = wm8350_ldo_disable,
.is_enabled = wm8350_ldo_is_enabled,
@ -1197,6 +1230,7 @@ static struct regulator_desc wm8350_reg[NUM_WM8350_REGULATORS] = {
.ops = &wm8350_dcdc_ops,
.irq = WM8350_IRQ_UV_DC1,
.type = REGULATOR_VOLTAGE,
.n_voltages = WM8350_DCDC_MAX_VSEL + 1,
.owner = THIS_MODULE,
},
{
@ -1213,6 +1247,7 @@ static struct regulator_desc wm8350_reg[NUM_WM8350_REGULATORS] = {
.ops = &wm8350_dcdc_ops,
.irq = WM8350_IRQ_UV_DC3,
.type = REGULATOR_VOLTAGE,
.n_voltages = WM8350_DCDC_MAX_VSEL + 1,
.owner = THIS_MODULE,
},
{
@ -1221,6 +1256,7 @@ static struct regulator_desc wm8350_reg[NUM_WM8350_REGULATORS] = {
.ops = &wm8350_dcdc_ops,
.irq = WM8350_IRQ_UV_DC4,
.type = REGULATOR_VOLTAGE,
.n_voltages = WM8350_DCDC_MAX_VSEL + 1,
.owner = THIS_MODULE,
},
{
@ -1237,6 +1273,7 @@ static struct regulator_desc wm8350_reg[NUM_WM8350_REGULATORS] = {
.ops = &wm8350_dcdc_ops,
.irq = WM8350_IRQ_UV_DC6,
.type = REGULATOR_VOLTAGE,
.n_voltages = WM8350_DCDC_MAX_VSEL + 1,
.owner = THIS_MODULE,
},
{
@ -1245,6 +1282,7 @@ static struct regulator_desc wm8350_reg[NUM_WM8350_REGULATORS] = {
.ops = &wm8350_ldo_ops,
.irq = WM8350_IRQ_UV_LDO1,
.type = REGULATOR_VOLTAGE,
.n_voltages = WM8350_LDO1_VSEL_MASK + 1,
.owner = THIS_MODULE,
},
{
@ -1253,6 +1291,7 @@ static struct regulator_desc wm8350_reg[NUM_WM8350_REGULATORS] = {
.ops = &wm8350_ldo_ops,
.irq = WM8350_IRQ_UV_LDO2,
.type = REGULATOR_VOLTAGE,
.n_voltages = WM8350_LDO2_VSEL_MASK + 1,
.owner = THIS_MODULE,
},
{
@ -1261,6 +1300,7 @@ static struct regulator_desc wm8350_reg[NUM_WM8350_REGULATORS] = {
.ops = &wm8350_ldo_ops,
.irq = WM8350_IRQ_UV_LDO3,
.type = REGULATOR_VOLTAGE,
.n_voltages = WM8350_LDO3_VSEL_MASK + 1,
.owner = THIS_MODULE,
},
{
@ -1269,6 +1309,7 @@ static struct regulator_desc wm8350_reg[NUM_WM8350_REGULATORS] = {
.ops = &wm8350_ldo_ops,
.irq = WM8350_IRQ_UV_LDO4,
.type = REGULATOR_VOLTAGE,
.n_voltages = WM8350_LDO4_VSEL_MASK + 1,
.owner = THIS_MODULE,
},
{
@ -1293,6 +1334,7 @@ static void pmic_uv_handler(struct wm8350 *wm8350, int irq, void *data)
{
struct regulator_dev *rdev = (struct regulator_dev *)data;
mutex_lock(&rdev->mutex);
if (irq == WM8350_IRQ_CS1 || irq == WM8350_IRQ_CS2)
regulator_notifier_call_chain(rdev,
REGULATOR_EVENT_REGULATION_OUT,
@ -1301,6 +1343,7 @@ static void pmic_uv_handler(struct wm8350 *wm8350, int irq, void *data)
regulator_notifier_call_chain(rdev,
REGULATOR_EVENT_UNDER_VOLTAGE,
wm8350);
mutex_unlock(&rdev->mutex);
}
static int wm8350_regulator_probe(struct platform_device *pdev)
@ -1333,9 +1376,9 @@ static int wm8350_regulator_probe(struct platform_device *pdev)
break;
}
/* register regulator */
rdev = regulator_register(&wm8350_reg[pdev->id], &pdev->dev,
pdev->dev.platform_data,
dev_get_drvdata(&pdev->dev));
if (IS_ERR(rdev)) {
dev_err(&pdev->dev, "failed to register %s\n",

View File

@ -43,6 +43,18 @@ static int wm8400_ldo_disable(struct regulator_dev *dev)
WM8400_LDO1_ENA, 0);
}
static int wm8400_ldo_list_voltage(struct regulator_dev *dev,
unsigned selector)
{
if (selector > WM8400_LDO1_VSEL_MASK)
return -EINVAL;
if (selector < 15)
return 900000 + (selector * 50000);
else
return 1600000 + ((selector - 14) * 100000);
}
static int wm8400_ldo_get_voltage(struct regulator_dev *dev)
{
struct wm8400 *wm8400 = rdev_get_drvdata(dev);
@ -51,10 +63,7 @@ static int wm8400_ldo_get_voltage(struct regulator_dev *dev)
val = wm8400_reg_read(wm8400, WM8400_LDO1_CONTROL + rdev_get_id(dev));
val &= WM8400_LDO1_VSEL_MASK;
if (val < 15)
return 900000 + (val * 50000);
else
return 1600000 + ((val - 14) * 100000);
return wm8400_ldo_list_voltage(dev, val);
}
static int wm8400_ldo_set_voltage(struct regulator_dev *dev,
@ -92,6 +101,7 @@ static struct regulator_ops wm8400_ldo_ops = {
.is_enabled = wm8400_ldo_is_enabled,
.enable = wm8400_ldo_enable,
.disable = wm8400_ldo_disable,
.list_voltage = wm8400_ldo_list_voltage,
.get_voltage = wm8400_ldo_get_voltage,
.set_voltage = wm8400_ldo_set_voltage,
};
@ -124,6 +134,15 @@ static int wm8400_dcdc_disable(struct regulator_dev *dev)
WM8400_DC1_ENA, 0);
}
static int wm8400_dcdc_list_voltage(struct regulator_dev *dev,
unsigned selector)
{
if (selector > WM8400_DC1_VSEL_MASK)
return -EINVAL;
return 850000 + (selector * 25000);
}
static int wm8400_dcdc_get_voltage(struct regulator_dev *dev)
{
struct wm8400 *wm8400 = rdev_get_drvdata(dev);
@ -237,6 +256,7 @@ static struct regulator_ops wm8400_dcdc_ops = {
.is_enabled = wm8400_dcdc_is_enabled,
.enable = wm8400_dcdc_enable,
.disable = wm8400_dcdc_disable,
.list_voltage = wm8400_dcdc_list_voltage,
.get_voltage = wm8400_dcdc_get_voltage,
.set_voltage = wm8400_dcdc_set_voltage,
.get_mode = wm8400_dcdc_get_mode,
@ -249,6 +269,7 @@ static struct regulator_desc regulators[] = {
.name = "LDO1",
.id = WM8400_LDO1,
.ops = &wm8400_ldo_ops,
.n_voltages = WM8400_LDO1_VSEL_MASK + 1,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
},
@ -256,6 +277,7 @@ static struct regulator_desc regulators[] = {
.name = "LDO2",
.id = WM8400_LDO2,
.ops = &wm8400_ldo_ops,
.n_voltages = WM8400_LDO2_VSEL_MASK + 1,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
},
@ -263,6 +285,7 @@ static struct regulator_desc regulators[] = {
.name = "LDO3",
.id = WM8400_LDO3,
.ops = &wm8400_ldo_ops,
.n_voltages = WM8400_LDO3_VSEL_MASK + 1,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
},
@ -270,6 +293,7 @@ static struct regulator_desc regulators[] = {
.name = "LDO4",
.id = WM8400_LDO4,
.ops = &wm8400_ldo_ops,
.n_voltages = WM8400_LDO4_VSEL_MASK + 1,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
},
@ -277,6 +301,7 @@ static struct regulator_desc regulators[] = {
.name = "DCDC1",
.id = WM8400_DCDC1,
.ops = &wm8400_dcdc_ops,
.n_voltages = WM8400_DC1_VSEL_MASK + 1,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
},
@ -284,6 +309,7 @@ static struct regulator_desc regulators[] = {
.name = "DCDC2",
.id = WM8400_DCDC2,
.ops = &wm8400_dcdc_ops,
.n_voltages = WM8400_DC2_VSEL_MASK + 1,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
},
@ -294,7 +320,7 @@ static int __devinit wm8400_regulator_probe(struct platform_device *pdev)
struct regulator_dev *rdev;
rdev = regulator_register(&regulators[pdev->id], &pdev->dev,
pdev->dev.driver_data);
pdev->dev.platform_data, pdev->dev.driver_data);
if (IS_ERR(rdev))
return PTR_ERR(rdev);

View File

@ -218,6 +218,53 @@ int twl4030_i2c_read(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes);
/*----------------------------------------------------------------------*/
/* Power bus message definitions */
#define DEV_GRP_NULL 0x0
#define DEV_GRP_P1 0x1
#define DEV_GRP_P2 0x2
#define DEV_GRP_P3 0x4
#define RES_GRP_RES 0x0
#define RES_GRP_PP 0x1
#define RES_GRP_RC 0x2
#define RES_GRP_PP_RC 0x3
#define RES_GRP_PR 0x4
#define RES_GRP_PP_PR 0x5
#define RES_GRP_RC_PR 0x6
#define RES_GRP_ALL 0x7
#define RES_TYPE2_R0 0x0
#define RES_TYPE_ALL 0x7
#define RES_STATE_WRST 0xF
#define RES_STATE_ACTIVE 0xE
#define RES_STATE_SLEEP 0x8
#define RES_STATE_OFF 0x0
/*
* Power Bus Message Format ... these can be sent individually by Linux,
* but are usually part of downloaded scripts that are run when various
* power events are triggered.
*
* Broadcast Message (16 Bits):
* DEV_GRP[15:13] MT[12] RES_GRP[11:9] RES_TYPE2[8:7] RES_TYPE[6:4]
* RES_STATE[3:0]
*
* Singular Message (16 Bits):
* DEV_GRP[15:13] MT[12] RES_ID[11:4] RES_STATE[3:0]
*/
#define MSG_BROADCAST(devgrp, grp, type, type2, state) \
( (devgrp) << 13 | 1 << 12 | (grp) << 9 | (type2) << 7 \
| (type) << 4 | (state))
#define MSG_SINGULAR(devgrp, id, state) \
((devgrp) << 13 | 0 << 12 | (id) << 4 | (state))
/*----------------------------------------------------------------------*/
struct twl4030_bci_platform_data {
int *battery_tmp_tbl;
unsigned int tblsize;

View File

@ -192,5 +192,10 @@ static inline void mmc_signal_sdio_irq(struct mmc_host *host)
wake_up_process(host->sdio_irq_thread);
}
struct regulator;
int mmc_regulator_get_ocrmask(struct regulator *supply);
int mmc_regulator_set_ocr(struct regulator *supply, unsigned short vdd_bit);
#endif

View File

@ -10,6 +10,8 @@
*
*/
struct regulator_init_data;
/**
* bq24022_mach_info - platform data for bq24022
* @gpio_nce: GPIO line connected to the nCE pin, used to enable / disable charging
@ -18,4 +20,5 @@
struct bq24022_mach_info {
int gpio_nce;
int gpio_iset2;
struct regulator_init_data *init_data;
};

View File

@ -3,7 +3,7 @@
*
* Copyright (C) 2007, 2008 Wolfson Microelectronics PLC.
*
* Author: Liam Girdwood <lg@opensource.wolfsonmicro.com>
* Author: Liam Girdwood <lrg@slimlogic.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@ -88,6 +88,7 @@
* FAIL Regulator output has failed.
* OVER_TEMP Regulator over temp.
* FORCE_DISABLE Regulator shut down by software.
* VOLTAGE_CHANGE Regulator voltage changed.
*
* NOTE: These events can be OR'ed together when passed into handler.
*/
@ -98,6 +99,7 @@
#define REGULATOR_EVENT_FAIL 0x08
#define REGULATOR_EVENT_OVER_TEMP 0x10
#define REGULATOR_EVENT_FORCE_DISABLE 0x20
#define REGULATOR_EVENT_VOLTAGE_CHANGE 0x40
struct regulator;
@ -140,6 +142,8 @@ int regulator_bulk_disable(int num_consumers,
void regulator_bulk_free(int num_consumers,
struct regulator_bulk_data *consumers);
int regulator_count_voltages(struct regulator *regulator);
int regulator_list_voltage(struct regulator *regulator, unsigned selector);
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,

View File

@ -3,7 +3,7 @@
*
* Copyright (C) 2007, 2008 Wolfson Microelectronics PLC.
*
* Author: Liam Girdwood <lg@opensource.wolfsonmicro.com>
* Author: Liam Girdwood <lrg@slimlogic.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@ -21,25 +21,38 @@
struct regulator_dev;
struct regulator_init_data;
enum regulator_status {
REGULATOR_STATUS_OFF,
REGULATOR_STATUS_ON,
REGULATOR_STATUS_ERROR,
/* fast/normal/idle/standby are flavors of "on" */
REGULATOR_STATUS_FAST,
REGULATOR_STATUS_NORMAL,
REGULATOR_STATUS_IDLE,
REGULATOR_STATUS_STANDBY,
};
/**
* struct regulator_ops - regulator operations.
*
* This struct describes regulator operations which can be implemented by
* regulator chip drivers.
*
* @enable: Enable the regulator.
* @disable: Disable the regulator.
* @enable: Configure the regulator as enabled.
* @disable: Configure the regulator as disabled.
* @is_enabled: Return 1 if the regulator is enabled, 0 otherwise.
*
* @set_voltage: Set the voltage for the regulator within the range specified.
* The driver should select the voltage closest to min_uV.
* @get_voltage: Return the currently configured voltage for the regulator.
* @list_voltage: Return one of the supported voltages, in microvolts; zero
* if the selector indicates a voltage that is unusable on this system;
* or negative errno. Selectors range from zero to one less than
* regulator_desc.n_voltages. Voltages may be reported in any order.
*
* @set_current_limit: Configure a limit for a current-limited regulator.
* @get_current_limit: Get the limit for a current-limited regulator.
* @get_current_limit: Get the configured limit for a current-limited regulator.
*
* @set_mode: Set the operating mode for the regulator.
* @get_mode: Get the current operating mode for the regulator.
* @get_mode: Get the configured operating mode for the regulator.
* @get_status: Return actual (not as-configured) status of regulator, as a
* REGULATOR_STATUS value (or negative errno)
* @get_optimum_mode: Get the most efficient operating mode for the regulator
* when running with the specified parameters.
*
@ -51,9 +64,15 @@ struct regulator_init_data;
* suspended.
* @set_suspend_mode: Set the operating mode for the regulator when the
* system is suspended.
*
* This struct describes regulator operations which can be implemented by
* regulator chip drivers.
*/
struct regulator_ops {
/* enumerate supported voltages */
int (*list_voltage) (struct regulator_dev *, unsigned selector);
/* get/set regulator voltage */
int (*set_voltage) (struct regulator_dev *, int min_uV, int max_uV);
int (*get_voltage) (struct regulator_dev *);
@ -72,6 +91,13 @@ struct regulator_ops {
int (*set_mode) (struct regulator_dev *, unsigned int mode);
unsigned int (*get_mode) (struct regulator_dev *);
/* report regulator status ... most other accessors report
* control inputs, this reports results of combining inputs
* from Linux (and other sources) with the actual load.
* returns REGULATOR_STATUS_* or negative errno.
*/
int (*get_status)(struct regulator_dev *);
/* get most efficient regulator operating mode for load */
unsigned int (*get_optimum_mode) (struct regulator_dev *, int input_uV,
int output_uV, int load_uA);
@ -106,6 +132,7 @@ enum regulator_type {
*
* @name: Identifying name for the regulator.
* @id: Numerical identifier for the regulator.
* @n_voltages: Number of selectors available for ops.list_voltage().
* @ops: Regulator operations table.
* @irq: Interrupt number for the regulator.
* @type: Indicates if the regulator is a voltage or current regulator.
@ -114,14 +141,48 @@ enum regulator_type {
struct regulator_desc {
const char *name;
int id;
unsigned n_voltages;
struct regulator_ops *ops;
int irq;
enum regulator_type type;
struct module *owner;
};
/*
* struct regulator_dev
*
* Voltage / Current regulator class device. One for each
* regulator.
*
* This should *not* be used directly by anything except the regulator
* core and notification injection (which should take the mutex and do
* no other direct access).
*/
struct regulator_dev {
struct regulator_desc *desc;
int use_count;
/* lists we belong to */
struct list_head list; /* list of all regulators */
struct list_head slist; /* list of supplied regulators */
/* lists we own */
struct list_head consumer_list; /* consumers we supply */
struct list_head supply_list; /* regulators we supply */
struct blocking_notifier_head notifier;
struct mutex mutex; /* consumer lock */
struct module *owner;
struct device dev;
struct regulation_constraints *constraints;
struct regulator_dev *supply; /* for tree */
void *reg_data; /* regulator_dev data */
};
struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc,
struct device *dev, void *driver_data);
struct device *dev, struct regulator_init_data *init_data,
void *driver_data);
void regulator_unregister(struct regulator_dev *rdev);
int regulator_notifier_call_chain(struct regulator_dev *rdev,

View File

@ -14,9 +14,12 @@
#ifndef __REGULATOR_FIXED_H
#define __REGULATOR_FIXED_H
struct regulator_init_data;
struct fixed_voltage_config {
const char *supply_name;
int microvolts;
struct regulator_init_data *init_data;
};
#endif

View File

@ -3,7 +3,7 @@
*
* Copyright (C) 2007, 2008 Wolfson Microelectronics PLC.
*
* Author: Liam Girdwood <lg@opensource.wolfsonmicro.com>
* Author: Liam Girdwood <lrg@slimlogic.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@ -73,7 +73,9 @@ struct regulator_state {
*
* @always_on: Set if the regulator should never be disabled.
* @boot_on: Set if the regulator is enabled when the system is initially
* started.
* started. If the regulator is not enabled by the hardware or
* bootloader then it will be enabled when the constraints are
* applied.
* @apply_uV: Apply the voltage constraint when initialising.
*
* @input_uV: Input voltage for regulator when supplied by another regulator.
@ -83,6 +85,7 @@ struct regulator_state {
* @state_standby: State for regulator when system is suspended in standby
* mode.
* @initial_state: Suspend state to set by default.
* @initial_mode: Mode to set at startup.
*/
struct regulation_constraints {
@ -111,6 +114,9 @@ struct regulation_constraints {
struct regulator_state state_standby;
suspend_state_t initial_state; /* suspend state to set at init */
/* mode to set on startup */
unsigned int initial_mode;
/* constriant flags */
unsigned always_on:1; /* regulator never off when system is on */
unsigned boot_on:1; /* bootloader/firmware enabled regulator */
@ -160,4 +166,6 @@ struct regulator_init_data {
int regulator_suspend_prepare(suspend_state_t state);
void regulator_has_full_constraints(void);
#endif