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:
Коммит
18b34b9546
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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, ®ulator_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 @@ overflow_err:
|
|||
* @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(®ulator_list_mutex);
|
||||
return regulator;
|
||||
|
||||
|
@ -961,10 +1068,6 @@ void regulator_put(struct regulator *regulator)
|
|||
mutex_lock(®ulator_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(®ulator->rdev->mutex);
|
||||
regulator->enabled = 0;
|
||||
regulator->uA_load = 0;
|
||||
ret = _regulator_force_disable(regulator->rdev);
|
||||
mutex_unlock(®ulator->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(®ulator_list_mutex);
|
||||
unset_regulator_supplies(rdev);
|
||||
list_del(&rdev->list);
|
||||
if (rdev->supply)
|
||||
sysfs_remove_link(&rdev->dev.kobj, "supply");
|
||||
|
@ -1988,6 +2143,23 @@ out:
|
|||
}
|
||||
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(®ulator_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, ®ulator_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(®ulator_list_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
late_initcall(regulator_init_complete);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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(®ulators[pdev->id], &pdev->dev, pcf);
|
||||
rdev = regulator_register(®ulators[pdev->id], &pdev->dev,
|
||||
pdev->dev.platform_data, pcf);
|
||||
if (IS_ERR(rdev))
|
||||
return PTR_ERR(rdev);
|
||||
|
||||
|
|
|
@ -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");
|
|
@ -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,
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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(®ulators[pdev->id], &pdev->dev,
|
||||
pdev->dev.driver_data);
|
||||
pdev->dev.platform_data, pdev->dev.driver_data);
|
||||
|
||||
if (IS_ERR(rdev))
|
||||
return PTR_ERR(rdev);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Загрузка…
Ссылка в новой задаче