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: (23 commits)
  regulator: Improve WM831x DVS VSEL selection algorithm
  regulator: Bootstrap wm831x DVS VSEL value from ON VSEL if not already set
  regulator: Set up GPIO for WM831x VSEL before enabling VSEL mode
  regulator: Add EPEs to the MODULE_ALIAS() for wm831x-dcdc
  regulator: Fix WM831x DCDC DVS VSEL bootstrapping
  regulator: Fix WM831x regulator ID lookups for multiple WM831xs
  regulator: Fix argument format type errors in error prints
  regulator: Fix memory leak in set_machine_constraints() error paths
  regulator: Make core more chatty about some errors
  regulator: tps65910: Fix array access out of bounds bug
  regulator: tps65910: Add missing breaks in switch/case
  regulator: tps65910: Fix a memory leak in tps65910_probe error path
  regulator: TWL: Remove entry of RES_ID for 6030 macros
  ASoC: tlv320aic3x: Add correct hw registers to Line1 cross connect muxes
  regulator: Add basic per consumer debugfs
  regulator: Add rdev_crit() macro
  regulator: Refactor supply implementation to work as regular consumers
  regulator: Include the device name in the microamps_requested_ file
  regulator: Increase the limit on sysfs file names
  regulator: Properly register dummy regulator driver
  ...
This commit is contained in:
Linus Torvalds 2011-08-01 14:05:46 -10:00
commit cfe22345ad
9 changed files with 310 additions and 201 deletions

View file

@ -20,6 +20,7 @@
#include <linux/debugfs.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/async.h>
#include <linux/err.h>
#include <linux/mutex.h>
#include <linux/suspend.h>
@ -33,6 +34,8 @@
#include "dummy.h"
#define rdev_crit(rdev, fmt, ...) \
pr_crit("%s: " fmt, rdev_get_name(rdev), ##__VA_ARGS__)
#define rdev_err(rdev, fmt, ...) \
pr_err("%s: " fmt, rdev_get_name(rdev), ##__VA_ARGS__)
#define rdev_warn(rdev, fmt, ...) \
@ -78,11 +81,13 @@ struct regulator {
char *supply_name;
struct device_attribute dev_attr;
struct regulator_dev *rdev;
#ifdef CONFIG_DEBUG_FS
struct dentry *debugfs;
#endif
};
static int _regulator_is_enabled(struct regulator_dev *rdev);
static int _regulator_disable(struct regulator_dev *rdev,
struct regulator_dev **supply_rdev_ptr);
static int _regulator_disable(struct regulator_dev *rdev);
static int _regulator_get_voltage(struct regulator_dev *rdev);
static int _regulator_get_current_limit(struct regulator_dev *rdev);
static unsigned int _regulator_get_mode(struct regulator_dev *rdev);
@ -90,6 +95,9 @@ static void _notifier_call_chain(struct regulator_dev *rdev,
unsigned long event, void *data);
static int _regulator_do_set_voltage(struct regulator_dev *rdev,
int min_uV, int max_uV);
static struct regulator *create_regulator(struct regulator_dev *rdev,
struct device *dev,
const char *supply_name);
static const char *rdev_get_name(struct regulator_dev *rdev)
{
@ -143,8 +151,11 @@ static int regulator_check_voltage(struct regulator_dev *rdev,
if (*min_uV < rdev->constraints->min_uV)
*min_uV = rdev->constraints->min_uV;
if (*min_uV > *max_uV)
if (*min_uV > *max_uV) {
rdev_err(rdev, "unsupportable voltage range: %d-%duV\n",
*min_uV, *max_uV);
return -EINVAL;
}
return 0;
}
@ -197,8 +208,11 @@ static int regulator_check_current_limit(struct regulator_dev *rdev,
if (*min_uA < rdev->constraints->min_uA)
*min_uA = rdev->constraints->min_uA;
if (*min_uA > *max_uA)
if (*min_uA > *max_uA) {
rdev_err(rdev, "unsupportable current range: %d-%duA\n",
*min_uA, *max_uA);
return -EINVAL;
}
return 0;
}
@ -213,6 +227,7 @@ static int regulator_mode_constrain(struct regulator_dev *rdev, int *mode)
case REGULATOR_MODE_STANDBY:
break;
default:
rdev_err(rdev, "invalid mode %x specified\n", *mode);
return -EINVAL;
}
@ -779,7 +794,6 @@ static int machine_constraints_voltage(struct regulator_dev *rdev,
if (ret < 0) {
rdev_err(rdev, "failed to apply %duV constraint\n",
rdev->constraints->min_uV);
rdev->constraints = NULL;
return ret;
}
}
@ -882,7 +896,6 @@ static int set_machine_constraints(struct regulator_dev *rdev,
ret = suspend_prepare(rdev, rdev->constraints->initial_state);
if (ret < 0) {
rdev_err(rdev, "failed to set suspend state\n");
rdev->constraints = NULL;
goto out;
}
}
@ -909,13 +922,15 @@ static int set_machine_constraints(struct regulator_dev *rdev,
ret = ops->enable(rdev);
if (ret < 0) {
rdev_err(rdev, "failed to enable\n");
rdev->constraints = NULL;
goto out;
}
}
print_constraints(rdev);
return 0;
out:
kfree(rdev->constraints);
rdev->constraints = NULL;
return ret;
}
@ -929,21 +944,20 @@ static int set_machine_constraints(struct regulator_dev *rdev,
* core if it's child is enabled.
*/
static int set_supply(struct regulator_dev *rdev,
struct regulator_dev *supply_rdev)
struct regulator_dev *supply_rdev)
{
int err;
err = sysfs_create_link(&rdev->dev.kobj, &supply_rdev->dev.kobj,
"supply");
if (err) {
rdev_err(rdev, "could not add device link %s err %d\n",
supply_rdev->dev.kobj.name, err);
goto out;
rdev_info(rdev, "supplied by %s\n", rdev_get_name(supply_rdev));
rdev->supply = create_regulator(supply_rdev, &rdev->dev, "SUPPLY");
if (IS_ERR(rdev->supply)) {
err = PTR_ERR(rdev->supply);
rdev->supply = NULL;
return err;
}
rdev->supply = supply_rdev;
list_add(&rdev->slist, &supply_rdev->supply_list);
out:
return err;
return 0;
}
/**
@ -1032,7 +1046,7 @@ static void unset_regulator_supplies(struct regulator_dev *rdev)
}
}
#define REG_STR_SIZE 32
#define REG_STR_SIZE 64
static struct regulator *create_regulator(struct regulator_dev *rdev,
struct device *dev,
@ -1052,8 +1066,9 @@ static struct regulator *create_regulator(struct regulator_dev *rdev,
if (dev) {
/* create a 'requested_microamps_name' sysfs entry */
size = scnprintf(buf, REG_STR_SIZE, "microamps_requested_%s",
supply_name);
size = scnprintf(buf, REG_STR_SIZE,
"microamps_requested_%s-%s",
dev_name(dev), supply_name);
if (size >= REG_STR_SIZE)
goto overflow_err;
@ -1088,7 +1103,28 @@ static struct regulator *create_regulator(struct regulator_dev *rdev,
dev->kobj.name, err);
goto link_name_err;
}
} else {
regulator->supply_name = kstrdup(supply_name, GFP_KERNEL);
if (regulator->supply_name == NULL)
goto attr_err;
}
#ifdef CONFIG_DEBUG_FS
regulator->debugfs = debugfs_create_dir(regulator->supply_name,
rdev->debugfs);
if (IS_ERR_OR_NULL(regulator->debugfs)) {
rdev_warn(rdev, "Failed to create debugfs directory\n");
regulator->debugfs = NULL;
} else {
debugfs_create_u32("uA_load", 0444, regulator->debugfs,
&regulator->uA_load);
debugfs_create_u32("min_uV", 0444, regulator->debugfs,
&regulator->min_uV);
debugfs_create_u32("max_uV", 0444, regulator->debugfs,
&regulator->max_uV);
}
#endif
mutex_unlock(&rdev->mutex);
return regulator;
link_name_err:
@ -1267,13 +1303,17 @@ void regulator_put(struct regulator *regulator)
mutex_lock(&regulator_list_mutex);
rdev = regulator->rdev;
#ifdef CONFIG_DEBUG_FS
debugfs_remove_recursive(regulator->debugfs);
#endif
/* remove any sysfs entries */
if (regulator->dev) {
sysfs_remove_link(&rdev->dev.kobj, regulator->supply_name);
kfree(regulator->supply_name);
device_remove_file(regulator->dev, &regulator->dev_attr);
kfree(regulator->dev_attr.attr.name);
}
kfree(regulator->supply_name);
list_del(&regulator->list);
kfree(regulator);
@ -1301,19 +1341,6 @@ static int _regulator_enable(struct regulator_dev *rdev)
{
int ret, delay;
if (rdev->use_count == 0) {
/* do we need to enable the supply regulator first */
if (rdev->supply) {
mutex_lock(&rdev->supply->mutex);
ret = _regulator_enable(rdev->supply);
mutex_unlock(&rdev->supply->mutex);
if (ret < 0) {
rdev_err(rdev, "failed to enable: %d\n", ret);
return ret;
}
}
}
/* check voltage and requested load before enabling */
if (rdev->constraints &&
(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_DRMS))
@ -1388,19 +1415,27 @@ int regulator_enable(struct regulator *regulator)
struct regulator_dev *rdev = regulator->rdev;
int ret = 0;
if (rdev->supply) {
ret = regulator_enable(rdev->supply);
if (ret != 0)
return ret;
}
mutex_lock(&rdev->mutex);
ret = _regulator_enable(rdev);
mutex_unlock(&rdev->mutex);
if (ret != 0)
regulator_disable(rdev->supply);
return ret;
}
EXPORT_SYMBOL_GPL(regulator_enable);
/* locks held by regulator_disable() */
static int _regulator_disable(struct regulator_dev *rdev,
struct regulator_dev **supply_rdev_ptr)
static int _regulator_disable(struct regulator_dev *rdev)
{
int ret = 0;
*supply_rdev_ptr = NULL;
if (WARN(rdev->use_count <= 0,
"unbalanced disables for %s\n", rdev_get_name(rdev)))
@ -1427,9 +1462,6 @@ static int _regulator_disable(struct regulator_dev *rdev,
NULL);
}
/* decrease our supplies ref count and disable if required */
*supply_rdev_ptr = rdev->supply;
rdev->use_count = 0;
} else if (rdev->use_count > 1) {
@ -1440,6 +1472,7 @@ static int _regulator_disable(struct regulator_dev *rdev,
rdev->use_count--;
}
return ret;
}
@ -1458,29 +1491,21 @@ static int _regulator_disable(struct regulator_dev *rdev,
int regulator_disable(struct regulator *regulator)
{
struct regulator_dev *rdev = regulator->rdev;
struct regulator_dev *supply_rdev = NULL;
int ret = 0;
mutex_lock(&rdev->mutex);
ret = _regulator_disable(rdev, &supply_rdev);
ret = _regulator_disable(rdev);
mutex_unlock(&rdev->mutex);
/* decrease our supplies ref count and disable if required */
while (supply_rdev != NULL) {
rdev = supply_rdev;
mutex_lock(&rdev->mutex);
_regulator_disable(rdev, &supply_rdev);
mutex_unlock(&rdev->mutex);
}
if (ret == 0 && rdev->supply)
regulator_disable(rdev->supply);
return ret;
}
EXPORT_SYMBOL_GPL(regulator_disable);
/* locks held by regulator_force_disable() */
static int _regulator_force_disable(struct regulator_dev *rdev,
struct regulator_dev **supply_rdev_ptr)
static int _regulator_force_disable(struct regulator_dev *rdev)
{
int ret = 0;
@ -1497,10 +1522,6 @@ static int _regulator_force_disable(struct regulator_dev *rdev,
REGULATOR_EVENT_DISABLE, NULL);
}
/* decrease our supplies ref count and disable if required */
*supply_rdev_ptr = rdev->supply;
rdev->use_count = 0;
return ret;
}
@ -1516,16 +1537,16 @@ static int _regulator_force_disable(struct regulator_dev *rdev,
int regulator_force_disable(struct regulator *regulator)
{
struct regulator_dev *rdev = regulator->rdev;
struct regulator_dev *supply_rdev = NULL;
int ret;
mutex_lock(&rdev->mutex);
regulator->uA_load = 0;
ret = _regulator_force_disable(rdev, &supply_rdev);
ret = _regulator_force_disable(regulator->rdev);
mutex_unlock(&rdev->mutex);
if (supply_rdev)
regulator_disable(get_device_regulator(rdev_get_dev(supply_rdev)));
if (rdev->supply)
while (rdev->open_count--)
regulator_disable(rdev->supply);
return ret;
}
@ -2136,7 +2157,7 @@ int regulator_set_optimum_mode(struct regulator *regulator, int uA_load)
/* get input voltage */
input_uV = 0;
if (rdev->supply)
input_uV = _regulator_get_voltage(rdev->supply);
input_uV = regulator_get_voltage(rdev->supply);
if (input_uV <= 0)
input_uV = rdev->constraints->input_uV;
if (input_uV <= 0) {
@ -2206,17 +2227,8 @@ EXPORT_SYMBOL_GPL(regulator_unregister_notifier);
static void _notifier_call_chain(struct regulator_dev *rdev,
unsigned long event, void *data)
{
struct regulator_dev *_rdev;
/* call rdev chain first */
blocking_notifier_call_chain(&rdev->notifier, event, NULL);
/* now notify regulator we supply */
list_for_each_entry(_rdev, &rdev->supply_list, slist) {
mutex_lock(&_rdev->mutex);
_notifier_call_chain(_rdev, event, data);
mutex_unlock(&_rdev->mutex);
}
}
/**
@ -2264,6 +2276,13 @@ int regulator_bulk_get(struct device *dev, int num_consumers,
}
EXPORT_SYMBOL_GPL(regulator_bulk_get);
static void regulator_bulk_enable_async(void *data, async_cookie_t cookie)
{
struct regulator_bulk_data *bulk = data;
bulk->ret = regulator_enable(bulk->consumer);
}
/**
* regulator_bulk_enable - enable multiple regulator consumers
*
@ -2279,21 +2298,33 @@ EXPORT_SYMBOL_GPL(regulator_bulk_get);
int regulator_bulk_enable(int num_consumers,
struct regulator_bulk_data *consumers)
{
LIST_HEAD(async_domain);
int i;
int ret;
int ret = 0;
for (i = 0; i < num_consumers; i++)
async_schedule_domain(regulator_bulk_enable_async,
&consumers[i], &async_domain);
async_synchronize_full_domain(&async_domain);
/* If any consumer failed we need to unwind any that succeeded */
for (i = 0; i < num_consumers; i++) {
ret = regulator_enable(consumers[i].consumer);
if (ret != 0)
if (consumers[i].ret != 0) {
ret = consumers[i].ret;
goto err;
}
}
return 0;
err:
pr_err("Failed to enable %s: %d\n", consumers[i].supply, ret);
for (--i; i >= 0; --i)
regulator_disable(consumers[i].consumer);
for (i = 0; i < num_consumers; i++)
if (consumers[i].ret == 0)
regulator_disable(consumers[i].consumer);
else
pr_err("Failed to enable %s: %d\n",
consumers[i].supply, consumers[i].ret);
return ret;
}
@ -2589,9 +2620,7 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc,
rdev->owner = regulator_desc->owner;
rdev->desc = regulator_desc;
INIT_LIST_HEAD(&rdev->consumer_list);
INIT_LIST_HEAD(&rdev->supply_list);
INIT_LIST_HEAD(&rdev->list);
INIT_LIST_HEAD(&rdev->slist);
BLOCKING_INIT_NOTIFIER_HEAD(&rdev->notifier);
/* preform any regulator specific init */
@ -2672,6 +2701,7 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc,
unset_regulator_supplies(rdev);
scrub:
kfree(rdev->constraints);
device_unregister(&rdev->dev);
/* device core frees rdev */
rdev = ERR_PTR(ret);
@ -2703,7 +2733,7 @@ void regulator_unregister(struct regulator_dev *rdev)
unset_regulator_supplies(rdev);
list_del(&rdev->list);
if (rdev->supply)
sysfs_remove_link(&rdev->dev.kobj, "supply");
regulator_put(rdev->supply);
device_unregister(&rdev->dev);
kfree(rdev->constraints);
mutex_unlock(&regulator_list_mutex);

View file

@ -36,6 +36,29 @@ static struct regulator_desc dummy_desc = {
.ops = &dummy_ops,
};
static int __devinit dummy_regulator_probe(struct platform_device *pdev)
{
int ret;
dummy_regulator_rdev = regulator_register(&dummy_desc, NULL,
&dummy_initdata, NULL);
if (IS_ERR(dummy_regulator_rdev)) {
ret = PTR_ERR(dummy_regulator_rdev);
pr_err("Failed to register regulator: %d\n", ret);
return ret;
}
return 0;
}
static struct platform_driver dummy_regulator_driver = {
.probe = dummy_regulator_probe,
.driver = {
.name = "reg-dummy",
.owner = THIS_MODULE,
},
};
static struct platform_device *dummy_pdev;
void __init regulator_dummy_init(void)
@ -55,12 +78,9 @@ void __init regulator_dummy_init(void)
return;
}
dummy_regulator_rdev = regulator_register(&dummy_desc, NULL,
&dummy_initdata, NULL);
if (IS_ERR(dummy_regulator_rdev)) {
ret = PTR_ERR(dummy_regulator_rdev);
pr_err("Failed to register regulator: %d\n", ret);
ret = platform_driver_register(&dummy_regulator_driver);
if (ret != 0) {
pr_err("Failed to register dummy regulator driver: %d\n", ret);
platform_device_unregister(dummy_pdev);
return;
}
}

View file

@ -49,7 +49,6 @@
#define TPS65911_REG_LDO7 11
#define TPS65911_REG_LDO8 12
#define TPS65910_NUM_REGULATOR 13
#define TPS65910_SUPPLY_STATE_ENABLED 0x1
/* supported VIO voltages in milivolts */
@ -264,11 +263,12 @@ static struct tps_info tps65911_regs[] = {
};
struct tps65910_reg {
struct regulator_desc desc[TPS65910_NUM_REGULATOR];
struct regulator_desc *desc;
struct tps65910 *mfd;
struct regulator_dev *rdev[TPS65910_NUM_REGULATOR];
struct tps_info *info[TPS65910_NUM_REGULATOR];
struct regulator_dev **rdev;
struct tps_info **info;
struct mutex mutex;
int num_regulators;
int mode;
int (*get_ctrl_reg)(int);
};
@ -759,8 +759,13 @@ static int tps65910_list_voltage_dcdc(struct regulator_dev *dev,
mult = (selector / VDD1_2_NUM_VOLTS) + 1;
volt = VDD1_2_MIN_VOLT +
(selector % VDD1_2_NUM_VOLTS) * VDD1_2_OFFSET;
break;
case TPS65911_REG_VDDCTRL:
volt = VDDCTRL_MIN_VOLT + (selector * VDDCTRL_OFFSET);
break;
default:
BUG();
return -EINVAL;
}
return volt * 100 * mult;
@ -897,16 +902,42 @@ static __devinit int tps65910_probe(struct platform_device *pdev)
switch(tps65910_chip_id(tps65910)) {
case TPS65910:
pmic->get_ctrl_reg = &tps65910_get_ctrl_register;
pmic->num_regulators = ARRAY_SIZE(tps65910_regs);
info = tps65910_regs;
break;
case TPS65911:
pmic->get_ctrl_reg = &tps65911_get_ctrl_register;
pmic->num_regulators = ARRAY_SIZE(tps65911_regs);
info = tps65911_regs;
break;
default:
pr_err("Invalid tps chip version\n");
kfree(pmic);
return -ENODEV;
}
for (i = 0; i < TPS65910_NUM_REGULATOR; i++, info++, reg_data++) {
pmic->desc = kcalloc(pmic->num_regulators,
sizeof(struct regulator_desc), GFP_KERNEL);
if (!pmic->desc) {
err = -ENOMEM;
goto err_free_pmic;
}
pmic->info = kcalloc(pmic->num_regulators,
sizeof(struct tps_info *), GFP_KERNEL);
if (!pmic->info) {
err = -ENOMEM;
goto err_free_desc;
}
pmic->rdev = kcalloc(pmic->num_regulators,
sizeof(struct regulator_dev *), GFP_KERNEL);
if (!pmic->rdev) {
err = -ENOMEM;
goto err_free_info;
}
for (i = 0; i < pmic->num_regulators; i++, info++, reg_data++) {
/* Register the regulators */
pmic->info[i] = info;
@ -938,7 +969,7 @@ static __devinit int tps65910_probe(struct platform_device *pdev)
"failed to register %s regulator\n",
pdev->name);
err = PTR_ERR(rdev);
goto err;
goto err_unregister_regulator;
}
/* Save regulator for cleanup */
@ -946,23 +977,31 @@ static __devinit int tps65910_probe(struct platform_device *pdev)
}
return 0;
err:
err_unregister_regulator:
while (--i >= 0)
regulator_unregister(pmic->rdev[i]);
kfree(pmic->rdev);
err_free_info:
kfree(pmic->info);
err_free_desc:
kfree(pmic->desc);
err_free_pmic:
kfree(pmic);
return err;
}
static int __devexit tps65910_remove(struct platform_device *pdev)
{
struct tps65910_reg *tps65910_reg = platform_get_drvdata(pdev);
struct tps65910_reg *pmic = platform_get_drvdata(pdev);
int i;
for (i = 0; i < TPS65910_NUM_REGULATOR; i++)
regulator_unregister(tps65910_reg->rdev[i]);
for (i = 0; i < pmic->num_regulators; i++)
regulator_unregister(pmic->rdev[i]);
kfree(tps65910_reg);
kfree(pmic->rdev);
kfree(pmic->info);
kfree(pmic->desc);
kfree(pmic);
return 0;
}

View file

@ -835,8 +835,8 @@ static struct regulator_ops twlsmps_ops = {
remap_conf) \
TWL_FIXED_LDO(label, offset, mVolts, num, turnon_delay, \
remap_conf, TWL4030, twl4030fixed_ops)
#define TWL6030_FIXED_LDO(label, offset, mVolts, num, turnon_delay) \
TWL_FIXED_LDO(label, offset, mVolts, num, turnon_delay, \
#define TWL6030_FIXED_LDO(label, offset, mVolts, turnon_delay) \
TWL_FIXED_LDO(label, offset, mVolts, 0x0, turnon_delay, \
0x0, TWL6030, twl6030fixed_ops)
#define TWL4030_ADJUSTABLE_LDO(label, offset, num, turnon_delay, remap_conf) { \
@ -856,24 +856,22 @@ static struct regulator_ops twlsmps_ops = {
}, \
}
#define TWL6030_ADJUSTABLE_LDO(label, offset, min_mVolts, max_mVolts, num) { \
#define TWL6030_ADJUSTABLE_LDO(label, offset, min_mVolts, max_mVolts) { \
.base = offset, \
.id = num, \
.min_mV = min_mVolts, \
.max_mV = max_mVolts, \
.desc = { \
.name = #label, \
.id = TWL6030_REG_##label, \
.n_voltages = (max_mVolts - min_mVolts)/100, \
.n_voltages = (max_mVolts - min_mVolts)/100 + 1, \
.ops = &twl6030ldo_ops, \
.type = REGULATOR_VOLTAGE, \
.owner = THIS_MODULE, \
}, \
}
#define TWL6025_ADJUSTABLE_LDO(label, offset, min_mVolts, max_mVolts, num) { \
#define TWL6025_ADJUSTABLE_LDO(label, offset, min_mVolts, max_mVolts) { \
.base = offset, \
.id = num, \
.min_mV = min_mVolts, \
.max_mV = max_mVolts, \
.desc = { \
@ -903,9 +901,8 @@ static struct regulator_ops twlsmps_ops = {
}, \
}
#define TWL6030_FIXED_RESOURCE(label, offset, num, turnon_delay) { \
#define TWL6030_FIXED_RESOURCE(label, offset, turnon_delay) { \
.base = offset, \
.id = num, \
.delay = turnon_delay, \
.desc = { \
.name = #label, \
@ -916,9 +913,8 @@ static struct regulator_ops twlsmps_ops = {
}, \
}
#define TWL6025_ADJUSTABLE_SMPS(label, offset, num) { \
#define TWL6025_ADJUSTABLE_SMPS(label, offset) { \
.base = offset, \
.id = num, \
.min_mV = 600, \
.max_mV = 2100, \
.desc = { \
@ -961,32 +957,32 @@ static struct twlreg_info twl_regs[] = {
/* 6030 REG with base as PMC Slave Misc : 0x0030 */
/* Turnon-delay and remap configuration values for 6030 are not
verified since the specification is not public */
TWL6030_ADJUSTABLE_LDO(VAUX1_6030, 0x54, 1000, 3300, 1),
TWL6030_ADJUSTABLE_LDO(VAUX2_6030, 0x58, 1000, 3300, 2),
TWL6030_ADJUSTABLE_LDO(VAUX3_6030, 0x5c, 1000, 3300, 3),
TWL6030_ADJUSTABLE_LDO(VMMC, 0x68, 1000, 3300, 4),
TWL6030_ADJUSTABLE_LDO(VPP, 0x6c, 1000, 3300, 5),
TWL6030_ADJUSTABLE_LDO(VUSIM, 0x74, 1000, 3300, 7),
TWL6030_FIXED_LDO(VANA, 0x50, 2100, 15, 0),
TWL6030_FIXED_LDO(VCXIO, 0x60, 1800, 16, 0),
TWL6030_FIXED_LDO(VDAC, 0x64, 1800, 17, 0),
TWL6030_FIXED_LDO(VUSB, 0x70, 3300, 18, 0),
TWL6030_FIXED_RESOURCE(CLK32KG, 0x8C, 48, 0),
TWL6030_ADJUSTABLE_LDO(VAUX1_6030, 0x54, 1000, 3300),
TWL6030_ADJUSTABLE_LDO(VAUX2_6030, 0x58, 1000, 3300),
TWL6030_ADJUSTABLE_LDO(VAUX3_6030, 0x5c, 1000, 3300),
TWL6030_ADJUSTABLE_LDO(VMMC, 0x68, 1000, 3300),
TWL6030_ADJUSTABLE_LDO(VPP, 0x6c, 1000, 3300),
TWL6030_ADJUSTABLE_LDO(VUSIM, 0x74, 1000, 3300),
TWL6030_FIXED_LDO(VANA, 0x50, 2100, 0),
TWL6030_FIXED_LDO(VCXIO, 0x60, 1800, 0),
TWL6030_FIXED_LDO(VDAC, 0x64, 1800, 0),
TWL6030_FIXED_LDO(VUSB, 0x70, 3300, 0),
TWL6030_FIXED_RESOURCE(CLK32KG, 0x8C, 0),
/* 6025 are renamed compared to 6030 versions */
TWL6025_ADJUSTABLE_LDO(LDO2, 0x54, 1000, 3300, 1),
TWL6025_ADJUSTABLE_LDO(LDO4, 0x58, 1000, 3300, 2),
TWL6025_ADJUSTABLE_LDO(LDO3, 0x5c, 1000, 3300, 3),
TWL6025_ADJUSTABLE_LDO(LDO5, 0x68, 1000, 3300, 4),
TWL6025_ADJUSTABLE_LDO(LDO1, 0x6c, 1000, 3300, 5),
TWL6025_ADJUSTABLE_LDO(LDO7, 0x74, 1000, 3300, 7),
TWL6025_ADJUSTABLE_LDO(LDO6, 0x60, 1000, 3300, 16),
TWL6025_ADJUSTABLE_LDO(LDOLN, 0x64, 1000, 3300, 17),
TWL6025_ADJUSTABLE_LDO(LDOUSB, 0x70, 1000, 3300, 18),
TWL6025_ADJUSTABLE_LDO(LDO2, 0x54, 1000, 3300),
TWL6025_ADJUSTABLE_LDO(LDO4, 0x58, 1000, 3300),
TWL6025_ADJUSTABLE_LDO(LDO3, 0x5c, 1000, 3300),
TWL6025_ADJUSTABLE_LDO(LDO5, 0x68, 1000, 3300),
TWL6025_ADJUSTABLE_LDO(LDO1, 0x6c, 1000, 3300),
TWL6025_ADJUSTABLE_LDO(LDO7, 0x74, 1000, 3300),
TWL6025_ADJUSTABLE_LDO(LDO6, 0x60, 1000, 3300),
TWL6025_ADJUSTABLE_LDO(LDOLN, 0x64, 1000, 3300),
TWL6025_ADJUSTABLE_LDO(LDOUSB, 0x70, 1000, 3300),
TWL6025_ADJUSTABLE_SMPS(SMPS3, 0x34, 1),
TWL6025_ADJUSTABLE_SMPS(SMPS4, 0x10, 2),
TWL6025_ADJUSTABLE_SMPS(VIO, 0x16, 3),
TWL6025_ADJUSTABLE_SMPS(SMPS3, 0x34),
TWL6025_ADJUSTABLE_SMPS(SMPS4, 0x10),
TWL6025_ADJUSTABLE_SMPS(VIO, 0x16),
};
static u8 twl_get_smps_offset(void)

View file

@ -267,23 +267,6 @@ static int wm831x_buckv_select_min_voltage(struct regulator_dev *rdev,
return vsel;
}
static int wm831x_buckv_select_max_voltage(struct regulator_dev *rdev,
int min_uV, int max_uV)
{
u16 vsel;
if (max_uV < 600000 || max_uV > 1800000)
return -EINVAL;
vsel = ((max_uV - 600000) / 12500) + 8;
if (wm831x_buckv_list_voltage(rdev, vsel) < min_uV ||
wm831x_buckv_list_voltage(rdev, vsel) < max_uV)
return -EINVAL;
return vsel;
}
static int wm831x_buckv_set_dvs(struct regulator_dev *rdev, int state)
{
struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev);
@ -338,28 +321,23 @@ static int wm831x_buckv_set_voltage(struct regulator_dev *rdev,
if (ret < 0)
return ret;
/* Set the high voltage as the DVS voltage. This is optimised
* for CPUfreq usage, most processors will keep the maximum
* voltage constant and lower the minimum with the frequency. */
vsel = wm831x_buckv_select_max_voltage(rdev, min_uV, max_uV);
if (vsel < 0) {
/* This should never happen - at worst the same vsel
* should be chosen */
WARN_ON(vsel < 0);
return 0;
/*
* If this VSEL is higher than the last one we've seen then
* remember it as the DVS VSEL. This is optimised for CPUfreq
* usage where we want to get to the highest voltage very
* quickly.
*/
if (vsel > dcdc->dvs_vsel) {
ret = wm831x_set_bits(wm831x, dvs_reg,
WM831X_DC1_DVS_VSEL_MASK,
dcdc->dvs_vsel);
if (ret == 0)
dcdc->dvs_vsel = vsel;
else
dev_warn(wm831x->dev,
"Failed to set DCDC DVS VSEL: %d\n", ret);
}
/* Don't bother if it's the same VSEL we're already using */
if (vsel == dcdc->on_vsel)
return 0;
ret = wm831x_set_bits(wm831x, dvs_reg, WM831X_DC1_DVS_VSEL_MASK, vsel);
if (ret == 0)
dcdc->dvs_vsel = vsel;
else
dev_warn(wm831x->dev, "Failed to set DCDC DVS VSEL: %d\n",
ret);
return 0;
}
@ -456,27 +434,6 @@ static __devinit void wm831x_buckv_dvs_init(struct wm831x_dcdc *dcdc,
if (!pdata || !pdata->dvs_gpio)
return;
switch (pdata->dvs_control_src) {
case 1:
ctrl = 2 << WM831X_DC1_DVS_SRC_SHIFT;
break;
case 2:
ctrl = 3 << WM831X_DC1_DVS_SRC_SHIFT;
break;
default:
dev_err(wm831x->dev, "Invalid DVS control source %d for %s\n",
pdata->dvs_control_src, dcdc->name);
return;
}
ret = wm831x_set_bits(wm831x, dcdc->base + WM831X_DCDC_DVS_CONTROL,
WM831X_DC1_DVS_SRC_MASK, ctrl);
if (ret < 0) {
dev_err(wm831x->dev, "Failed to set %s DVS source: %d\n",
dcdc->name, ret);
return;
}
ret = gpio_request(pdata->dvs_gpio, "DCDC DVS");
if (ret < 0) {
dev_err(wm831x->dev, "Failed to get %s DVS GPIO: %d\n",
@ -498,17 +455,57 @@ static __devinit void wm831x_buckv_dvs_init(struct wm831x_dcdc *dcdc,
}
dcdc->dvs_gpio = pdata->dvs_gpio;
switch (pdata->dvs_control_src) {
case 1:
ctrl = 2 << WM831X_DC1_DVS_SRC_SHIFT;
break;
case 2:
ctrl = 3 << WM831X_DC1_DVS_SRC_SHIFT;
break;
default:
dev_err(wm831x->dev, "Invalid DVS control source %d for %s\n",
pdata->dvs_control_src, dcdc->name);
return;
}
/* If DVS_VSEL is set to the minimum value then raise it to ON_VSEL
* to make bootstrapping a bit smoother.
*/
if (!dcdc->dvs_vsel) {
ret = wm831x_set_bits(wm831x,
dcdc->base + WM831X_DCDC_DVS_CONTROL,
WM831X_DC1_DVS_VSEL_MASK, dcdc->on_vsel);
if (ret == 0)
dcdc->dvs_vsel = dcdc->on_vsel;
else
dev_warn(wm831x->dev, "Failed to set DVS_VSEL: %d\n",
ret);
}
ret = wm831x_set_bits(wm831x, dcdc->base + WM831X_DCDC_DVS_CONTROL,
WM831X_DC1_DVS_SRC_MASK, ctrl);
if (ret < 0) {
dev_err(wm831x->dev, "Failed to set %s DVS source: %d\n",
dcdc->name, ret);
}
}
static __devinit int wm831x_buckv_probe(struct platform_device *pdev)
{
struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
struct wm831x_pdata *pdata = wm831x->dev->platform_data;
int id = pdev->id % ARRAY_SIZE(pdata->dcdc);
int id;
struct wm831x_dcdc *dcdc;
struct resource *res;
int ret, irq;
if (pdata && pdata->wm831x_num)
id = (pdata->wm831x_num * 10) + 1;
else
id = 0;
id = pdev->id - id;
dev_dbg(&pdev->dev, "Probing DCDC%d\n", id + 1);
if (pdata == NULL || pdata->dcdc[id] == NULL)
@ -545,7 +542,7 @@ static __devinit int wm831x_buckv_probe(struct platform_device *pdev)
}
dcdc->on_vsel = ret & WM831X_DC1_ON_VSEL_MASK;
ret = wm831x_reg_read(wm831x, dcdc->base + WM831X_DCDC_ON_CONFIG);
ret = wm831x_reg_read(wm831x, dcdc->base + WM831X_DCDC_DVS_CONTROL);
if (ret < 0) {
dev_err(wm831x->dev, "Failed to read DVS VSEL: %d\n", ret);
goto err;
@ -709,11 +706,17 @@ static __devinit int wm831x_buckp_probe(struct platform_device *pdev)
{
struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
struct wm831x_pdata *pdata = wm831x->dev->platform_data;
int id = pdev->id % ARRAY_SIZE(pdata->dcdc);
int id;
struct wm831x_dcdc *dcdc;
struct resource *res;
int ret, irq;
if (pdata && pdata->wm831x_num)
id = (pdata->wm831x_num * 10) + 1;
else
id = 0;
id = pdev->id - id;
dev_dbg(&pdev->dev, "Probing DCDC%d\n", id + 1);
if (pdata == NULL || pdata->dcdc[id] == NULL)
@ -1046,3 +1049,4 @@ MODULE_DESCRIPTION("WM831x DC-DC convertor driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:wm831x-buckv");
MODULE_ALIAS("platform:wm831x-buckp");
MODULE_ALIAS("platform:wm831x-epe");

View file

@ -310,11 +310,17 @@ static __devinit int wm831x_gp_ldo_probe(struct platform_device *pdev)
{
struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
struct wm831x_pdata *pdata = wm831x->dev->platform_data;
int id = pdev->id % ARRAY_SIZE(pdata->ldo);
int id;
struct wm831x_ldo *ldo;
struct resource *res;
int ret, irq;
if (pdata && pdata->wm831x_num)
id = (pdata->wm831x_num * 10) + 1;
else
id = 0;
id = pdev->id - id;
dev_dbg(&pdev->dev, "Probing LDO%d\n", id + 1);
if (pdata == NULL || pdata->ldo[id] == NULL)
@ -574,11 +580,17 @@ static __devinit int wm831x_aldo_probe(struct platform_device *pdev)
{
struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
struct wm831x_pdata *pdata = wm831x->dev->platform_data;
int id = pdev->id % ARRAY_SIZE(pdata->ldo);
int id;
struct wm831x_ldo *ldo;
struct resource *res;
int ret, irq;
if (pdata && pdata->wm831x_num)
id = (pdata->wm831x_num * 10) + 1;
else
id = 0;
id = pdev->id - id;
dev_dbg(&pdev->dev, "Probing LDO%d\n", id + 1);
if (pdata == NULL || pdata->ldo[id] == NULL)
@ -764,11 +776,18 @@ static __devinit int wm831x_alive_ldo_probe(struct platform_device *pdev)
{
struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
struct wm831x_pdata *pdata = wm831x->dev->platform_data;
int id = pdev->id % ARRAY_SIZE(pdata->ldo);
int id;
struct wm831x_ldo *ldo;
struct resource *res;
int ret;
if (pdata && pdata->wm831x_num)
id = (pdata->wm831x_num * 10) + 1;
else
id = 0;
id = pdev->id - id;
dev_dbg(&pdev->dev, "Probing LDO%d\n", id + 1);
if (pdata == NULL || pdata->ldo[id] == NULL)

View file

@ -43,7 +43,7 @@ static int wm8994_ldo_enable(struct regulator_dev *rdev)
if (!ldo->enable)
return 0;
gpio_set_value(ldo->enable, 1);
gpio_set_value_cansleep(ldo->enable, 1);
ldo->is_enabled = true;
return 0;
@ -57,7 +57,7 @@ static int wm8994_ldo_disable(struct regulator_dev *rdev)
if (!ldo->enable)
return -EINVAL;
gpio_set_value(ldo->enable, 0);
gpio_set_value_cansleep(ldo->enable, 0);
ldo->is_enabled = false;
return 0;

View file

@ -122,6 +122,9 @@ struct regulator;
struct regulator_bulk_data {
const char *supply;
struct regulator *consumer;
/* Internal use */
int ret;
};
#if defined(CONFIG_REGULATOR)

View file

@ -188,18 +188,16 @@ struct regulator_dev {
/* 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 */
struct regulator *supply; /* for tree */
void *reg_data; /* regulator_dev data */