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:
commit
cfe22345ad
9 changed files with 310 additions and 201 deletions
|
@ -20,6 +20,7 @@
|
||||||
#include <linux/debugfs.h>
|
#include <linux/debugfs.h>
|
||||||
#include <linux/device.h>
|
#include <linux/device.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
|
#include <linux/async.h>
|
||||||
#include <linux/err.h>
|
#include <linux/err.h>
|
||||||
#include <linux/mutex.h>
|
#include <linux/mutex.h>
|
||||||
#include <linux/suspend.h>
|
#include <linux/suspend.h>
|
||||||
|
@ -33,6 +34,8 @@
|
||||||
|
|
||||||
#include "dummy.h"
|
#include "dummy.h"
|
||||||
|
|
||||||
|
#define rdev_crit(rdev, fmt, ...) \
|
||||||
|
pr_crit("%s: " fmt, rdev_get_name(rdev), ##__VA_ARGS__)
|
||||||
#define rdev_err(rdev, fmt, ...) \
|
#define rdev_err(rdev, fmt, ...) \
|
||||||
pr_err("%s: " fmt, rdev_get_name(rdev), ##__VA_ARGS__)
|
pr_err("%s: " fmt, rdev_get_name(rdev), ##__VA_ARGS__)
|
||||||
#define rdev_warn(rdev, fmt, ...) \
|
#define rdev_warn(rdev, fmt, ...) \
|
||||||
|
@ -78,11 +81,13 @@ struct regulator {
|
||||||
char *supply_name;
|
char *supply_name;
|
||||||
struct device_attribute dev_attr;
|
struct device_attribute dev_attr;
|
||||||
struct regulator_dev *rdev;
|
struct regulator_dev *rdev;
|
||||||
|
#ifdef CONFIG_DEBUG_FS
|
||||||
|
struct dentry *debugfs;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
static int _regulator_is_enabled(struct regulator_dev *rdev);
|
static int _regulator_is_enabled(struct regulator_dev *rdev);
|
||||||
static int _regulator_disable(struct regulator_dev *rdev,
|
static int _regulator_disable(struct regulator_dev *rdev);
|
||||||
struct regulator_dev **supply_rdev_ptr);
|
|
||||||
static int _regulator_get_voltage(struct regulator_dev *rdev);
|
static int _regulator_get_voltage(struct regulator_dev *rdev);
|
||||||
static int _regulator_get_current_limit(struct regulator_dev *rdev);
|
static int _regulator_get_current_limit(struct regulator_dev *rdev);
|
||||||
static unsigned int _regulator_get_mode(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);
|
unsigned long event, void *data);
|
||||||
static int _regulator_do_set_voltage(struct regulator_dev *rdev,
|
static int _regulator_do_set_voltage(struct regulator_dev *rdev,
|
||||||
int min_uV, int max_uV);
|
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)
|
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)
|
if (*min_uV < rdev->constraints->min_uV)
|
||||||
*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 -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -197,8 +208,11 @@ static int regulator_check_current_limit(struct regulator_dev *rdev,
|
||||||
if (*min_uA < rdev->constraints->min_uA)
|
if (*min_uA < rdev->constraints->min_uA)
|
||||||
*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 -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -213,6 +227,7 @@ static int regulator_mode_constrain(struct regulator_dev *rdev, int *mode)
|
||||||
case REGULATOR_MODE_STANDBY:
|
case REGULATOR_MODE_STANDBY:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
rdev_err(rdev, "invalid mode %x specified\n", *mode);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -779,7 +794,6 @@ static int machine_constraints_voltage(struct regulator_dev *rdev,
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
rdev_err(rdev, "failed to apply %duV constraint\n",
|
rdev_err(rdev, "failed to apply %duV constraint\n",
|
||||||
rdev->constraints->min_uV);
|
rdev->constraints->min_uV);
|
||||||
rdev->constraints = NULL;
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -882,7 +896,6 @@ static int set_machine_constraints(struct regulator_dev *rdev,
|
||||||
ret = suspend_prepare(rdev, rdev->constraints->initial_state);
|
ret = suspend_prepare(rdev, rdev->constraints->initial_state);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
rdev_err(rdev, "failed to set suspend state\n");
|
rdev_err(rdev, "failed to set suspend state\n");
|
||||||
rdev->constraints = NULL;
|
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -909,13 +922,15 @@ static int set_machine_constraints(struct regulator_dev *rdev,
|
||||||
ret = ops->enable(rdev);
|
ret = ops->enable(rdev);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
rdev_err(rdev, "failed to enable\n");
|
rdev_err(rdev, "failed to enable\n");
|
||||||
rdev->constraints = NULL;
|
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
print_constraints(rdev);
|
print_constraints(rdev);
|
||||||
|
return 0;
|
||||||
out:
|
out:
|
||||||
|
kfree(rdev->constraints);
|
||||||
|
rdev->constraints = NULL;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -929,21 +944,20 @@ static int set_machine_constraints(struct regulator_dev *rdev,
|
||||||
* core if it's child is enabled.
|
* core if it's child is enabled.
|
||||||
*/
|
*/
|
||||||
static int set_supply(struct regulator_dev *rdev,
|
static int set_supply(struct regulator_dev *rdev,
|
||||||
struct regulator_dev *supply_rdev)
|
struct regulator_dev *supply_rdev)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
err = sysfs_create_link(&rdev->dev.kobj, &supply_rdev->dev.kobj,
|
rdev_info(rdev, "supplied by %s\n", rdev_get_name(supply_rdev));
|
||||||
"supply");
|
|
||||||
if (err) {
|
rdev->supply = create_regulator(supply_rdev, &rdev->dev, "SUPPLY");
|
||||||
rdev_err(rdev, "could not add device link %s err %d\n",
|
if (IS_ERR(rdev->supply)) {
|
||||||
supply_rdev->dev.kobj.name, err);
|
err = PTR_ERR(rdev->supply);
|
||||||
goto out;
|
rdev->supply = NULL;
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
rdev->supply = supply_rdev;
|
|
||||||
list_add(&rdev->slist, &supply_rdev->supply_list);
|
return 0;
|
||||||
out:
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -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,
|
static struct regulator *create_regulator(struct regulator_dev *rdev,
|
||||||
struct device *dev,
|
struct device *dev,
|
||||||
|
@ -1052,8 +1066,9 @@ static struct regulator *create_regulator(struct regulator_dev *rdev,
|
||||||
|
|
||||||
if (dev) {
|
if (dev) {
|
||||||
/* create a 'requested_microamps_name' sysfs entry */
|
/* create a 'requested_microamps_name' sysfs entry */
|
||||||
size = scnprintf(buf, REG_STR_SIZE, "microamps_requested_%s",
|
size = scnprintf(buf, REG_STR_SIZE,
|
||||||
supply_name);
|
"microamps_requested_%s-%s",
|
||||||
|
dev_name(dev), supply_name);
|
||||||
if (size >= REG_STR_SIZE)
|
if (size >= REG_STR_SIZE)
|
||||||
goto overflow_err;
|
goto overflow_err;
|
||||||
|
|
||||||
|
@ -1088,7 +1103,28 @@ static struct regulator *create_regulator(struct regulator_dev *rdev,
|
||||||
dev->kobj.name, err);
|
dev->kobj.name, err);
|
||||||
goto link_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,
|
||||||
|
®ulator->uA_load);
|
||||||
|
debugfs_create_u32("min_uV", 0444, regulator->debugfs,
|
||||||
|
®ulator->min_uV);
|
||||||
|
debugfs_create_u32("max_uV", 0444, regulator->debugfs,
|
||||||
|
®ulator->max_uV);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
mutex_unlock(&rdev->mutex);
|
mutex_unlock(&rdev->mutex);
|
||||||
return regulator;
|
return regulator;
|
||||||
link_name_err:
|
link_name_err:
|
||||||
|
@ -1267,13 +1303,17 @@ void regulator_put(struct regulator *regulator)
|
||||||
mutex_lock(®ulator_list_mutex);
|
mutex_lock(®ulator_list_mutex);
|
||||||
rdev = regulator->rdev;
|
rdev = regulator->rdev;
|
||||||
|
|
||||||
|
#ifdef CONFIG_DEBUG_FS
|
||||||
|
debugfs_remove_recursive(regulator->debugfs);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* remove any sysfs entries */
|
/* remove any sysfs entries */
|
||||||
if (regulator->dev) {
|
if (regulator->dev) {
|
||||||
sysfs_remove_link(&rdev->dev.kobj, regulator->supply_name);
|
sysfs_remove_link(&rdev->dev.kobj, regulator->supply_name);
|
||||||
kfree(regulator->supply_name);
|
|
||||||
device_remove_file(regulator->dev, ®ulator->dev_attr);
|
device_remove_file(regulator->dev, ®ulator->dev_attr);
|
||||||
kfree(regulator->dev_attr.attr.name);
|
kfree(regulator->dev_attr.attr.name);
|
||||||
}
|
}
|
||||||
|
kfree(regulator->supply_name);
|
||||||
list_del(®ulator->list);
|
list_del(®ulator->list);
|
||||||
kfree(regulator);
|
kfree(regulator);
|
||||||
|
|
||||||
|
@ -1301,19 +1341,6 @@ static int _regulator_enable(struct regulator_dev *rdev)
|
||||||
{
|
{
|
||||||
int ret, delay;
|
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 */
|
/* check voltage and requested load before enabling */
|
||||||
if (rdev->constraints &&
|
if (rdev->constraints &&
|
||||||
(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_DRMS))
|
(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_DRMS))
|
||||||
|
@ -1388,19 +1415,27 @@ int regulator_enable(struct regulator *regulator)
|
||||||
struct regulator_dev *rdev = regulator->rdev;
|
struct regulator_dev *rdev = regulator->rdev;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
|
if (rdev->supply) {
|
||||||
|
ret = regulator_enable(rdev->supply);
|
||||||
|
if (ret != 0)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
mutex_lock(&rdev->mutex);
|
mutex_lock(&rdev->mutex);
|
||||||
ret = _regulator_enable(rdev);
|
ret = _regulator_enable(rdev);
|
||||||
mutex_unlock(&rdev->mutex);
|
mutex_unlock(&rdev->mutex);
|
||||||
|
|
||||||
|
if (ret != 0)
|
||||||
|
regulator_disable(rdev->supply);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(regulator_enable);
|
EXPORT_SYMBOL_GPL(regulator_enable);
|
||||||
|
|
||||||
/* locks held by regulator_disable() */
|
/* locks held by regulator_disable() */
|
||||||
static int _regulator_disable(struct regulator_dev *rdev,
|
static int _regulator_disable(struct regulator_dev *rdev)
|
||||||
struct regulator_dev **supply_rdev_ptr)
|
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
*supply_rdev_ptr = NULL;
|
|
||||||
|
|
||||||
if (WARN(rdev->use_count <= 0,
|
if (WARN(rdev->use_count <= 0,
|
||||||
"unbalanced disables for %s\n", rdev_get_name(rdev)))
|
"unbalanced disables for %s\n", rdev_get_name(rdev)))
|
||||||
|
@ -1427,9 +1462,6 @@ static int _regulator_disable(struct regulator_dev *rdev,
|
||||||
NULL);
|
NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* decrease our supplies ref count and disable if required */
|
|
||||||
*supply_rdev_ptr = rdev->supply;
|
|
||||||
|
|
||||||
rdev->use_count = 0;
|
rdev->use_count = 0;
|
||||||
} else if (rdev->use_count > 1) {
|
} else if (rdev->use_count > 1) {
|
||||||
|
|
||||||
|
@ -1440,6 +1472,7 @@ static int _regulator_disable(struct regulator_dev *rdev,
|
||||||
|
|
||||||
rdev->use_count--;
|
rdev->use_count--;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1458,29 +1491,21 @@ static int _regulator_disable(struct regulator_dev *rdev,
|
||||||
int regulator_disable(struct regulator *regulator)
|
int regulator_disable(struct regulator *regulator)
|
||||||
{
|
{
|
||||||
struct regulator_dev *rdev = regulator->rdev;
|
struct regulator_dev *rdev = regulator->rdev;
|
||||||
struct regulator_dev *supply_rdev = NULL;
|
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
mutex_lock(&rdev->mutex);
|
mutex_lock(&rdev->mutex);
|
||||||
ret = _regulator_disable(rdev, &supply_rdev);
|
ret = _regulator_disable(rdev);
|
||||||
mutex_unlock(&rdev->mutex);
|
mutex_unlock(&rdev->mutex);
|
||||||
|
|
||||||
/* decrease our supplies ref count and disable if required */
|
if (ret == 0 && rdev->supply)
|
||||||
while (supply_rdev != NULL) {
|
regulator_disable(rdev->supply);
|
||||||
rdev = supply_rdev;
|
|
||||||
|
|
||||||
mutex_lock(&rdev->mutex);
|
|
||||||
_regulator_disable(rdev, &supply_rdev);
|
|
||||||
mutex_unlock(&rdev->mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(regulator_disable);
|
EXPORT_SYMBOL_GPL(regulator_disable);
|
||||||
|
|
||||||
/* locks held by regulator_force_disable() */
|
/* locks held by regulator_force_disable() */
|
||||||
static int _regulator_force_disable(struct regulator_dev *rdev,
|
static int _regulator_force_disable(struct regulator_dev *rdev)
|
||||||
struct regulator_dev **supply_rdev_ptr)
|
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
|
@ -1497,10 +1522,6 @@ static int _regulator_force_disable(struct regulator_dev *rdev,
|
||||||
REGULATOR_EVENT_DISABLE, NULL);
|
REGULATOR_EVENT_DISABLE, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* decrease our supplies ref count and disable if required */
|
|
||||||
*supply_rdev_ptr = rdev->supply;
|
|
||||||
|
|
||||||
rdev->use_count = 0;
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1516,16 +1537,16 @@ static int _regulator_force_disable(struct regulator_dev *rdev,
|
||||||
int regulator_force_disable(struct regulator *regulator)
|
int regulator_force_disable(struct regulator *regulator)
|
||||||
{
|
{
|
||||||
struct regulator_dev *rdev = regulator->rdev;
|
struct regulator_dev *rdev = regulator->rdev;
|
||||||
struct regulator_dev *supply_rdev = NULL;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
mutex_lock(&rdev->mutex);
|
mutex_lock(&rdev->mutex);
|
||||||
regulator->uA_load = 0;
|
regulator->uA_load = 0;
|
||||||
ret = _regulator_force_disable(rdev, &supply_rdev);
|
ret = _regulator_force_disable(regulator->rdev);
|
||||||
mutex_unlock(&rdev->mutex);
|
mutex_unlock(&rdev->mutex);
|
||||||
|
|
||||||
if (supply_rdev)
|
if (rdev->supply)
|
||||||
regulator_disable(get_device_regulator(rdev_get_dev(supply_rdev)));
|
while (rdev->open_count--)
|
||||||
|
regulator_disable(rdev->supply);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -2136,7 +2157,7 @@ int regulator_set_optimum_mode(struct regulator *regulator, int uA_load)
|
||||||
/* get input voltage */
|
/* get input voltage */
|
||||||
input_uV = 0;
|
input_uV = 0;
|
||||||
if (rdev->supply)
|
if (rdev->supply)
|
||||||
input_uV = _regulator_get_voltage(rdev->supply);
|
input_uV = regulator_get_voltage(rdev->supply);
|
||||||
if (input_uV <= 0)
|
if (input_uV <= 0)
|
||||||
input_uV = rdev->constraints->input_uV;
|
input_uV = rdev->constraints->input_uV;
|
||||||
if (input_uV <= 0) {
|
if (input_uV <= 0) {
|
||||||
|
@ -2206,17 +2227,8 @@ EXPORT_SYMBOL_GPL(regulator_unregister_notifier);
|
||||||
static void _notifier_call_chain(struct regulator_dev *rdev,
|
static void _notifier_call_chain(struct regulator_dev *rdev,
|
||||||
unsigned long event, void *data)
|
unsigned long event, void *data)
|
||||||
{
|
{
|
||||||
struct regulator_dev *_rdev;
|
|
||||||
|
|
||||||
/* call rdev chain first */
|
/* call rdev chain first */
|
||||||
blocking_notifier_call_chain(&rdev->notifier, event, NULL);
|
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);
|
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
|
* regulator_bulk_enable - enable multiple regulator consumers
|
||||||
*
|
*
|
||||||
|
@ -2279,21 +2298,33 @@ EXPORT_SYMBOL_GPL(regulator_bulk_get);
|
||||||
int regulator_bulk_enable(int num_consumers,
|
int regulator_bulk_enable(int num_consumers,
|
||||||
struct regulator_bulk_data *consumers)
|
struct regulator_bulk_data *consumers)
|
||||||
{
|
{
|
||||||
|
LIST_HEAD(async_domain);
|
||||||
int i;
|
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++) {
|
for (i = 0; i < num_consumers; i++) {
|
||||||
ret = regulator_enable(consumers[i].consumer);
|
if (consumers[i].ret != 0) {
|
||||||
if (ret != 0)
|
ret = consumers[i].ret;
|
||||||
goto err;
|
goto err;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
pr_err("Failed to enable %s: %d\n", consumers[i].supply, ret);
|
for (i = 0; i < num_consumers; i++)
|
||||||
for (--i; i >= 0; --i)
|
if (consumers[i].ret == 0)
|
||||||
regulator_disable(consumers[i].consumer);
|
regulator_disable(consumers[i].consumer);
|
||||||
|
else
|
||||||
|
pr_err("Failed to enable %s: %d\n",
|
||||||
|
consumers[i].supply, consumers[i].ret);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -2589,9 +2620,7 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc,
|
||||||
rdev->owner = regulator_desc->owner;
|
rdev->owner = regulator_desc->owner;
|
||||||
rdev->desc = regulator_desc;
|
rdev->desc = regulator_desc;
|
||||||
INIT_LIST_HEAD(&rdev->consumer_list);
|
INIT_LIST_HEAD(&rdev->consumer_list);
|
||||||
INIT_LIST_HEAD(&rdev->supply_list);
|
|
||||||
INIT_LIST_HEAD(&rdev->list);
|
INIT_LIST_HEAD(&rdev->list);
|
||||||
INIT_LIST_HEAD(&rdev->slist);
|
|
||||||
BLOCKING_INIT_NOTIFIER_HEAD(&rdev->notifier);
|
BLOCKING_INIT_NOTIFIER_HEAD(&rdev->notifier);
|
||||||
|
|
||||||
/* preform any regulator specific init */
|
/* preform any regulator specific init */
|
||||||
|
@ -2672,6 +2701,7 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc,
|
||||||
unset_regulator_supplies(rdev);
|
unset_regulator_supplies(rdev);
|
||||||
|
|
||||||
scrub:
|
scrub:
|
||||||
|
kfree(rdev->constraints);
|
||||||
device_unregister(&rdev->dev);
|
device_unregister(&rdev->dev);
|
||||||
/* device core frees rdev */
|
/* device core frees rdev */
|
||||||
rdev = ERR_PTR(ret);
|
rdev = ERR_PTR(ret);
|
||||||
|
@ -2703,7 +2733,7 @@ void regulator_unregister(struct regulator_dev *rdev)
|
||||||
unset_regulator_supplies(rdev);
|
unset_regulator_supplies(rdev);
|
||||||
list_del(&rdev->list);
|
list_del(&rdev->list);
|
||||||
if (rdev->supply)
|
if (rdev->supply)
|
||||||
sysfs_remove_link(&rdev->dev.kobj, "supply");
|
regulator_put(rdev->supply);
|
||||||
device_unregister(&rdev->dev);
|
device_unregister(&rdev->dev);
|
||||||
kfree(rdev->constraints);
|
kfree(rdev->constraints);
|
||||||
mutex_unlock(®ulator_list_mutex);
|
mutex_unlock(®ulator_list_mutex);
|
||||||
|
|
|
@ -36,6 +36,29 @@ static struct regulator_desc dummy_desc = {
|
||||||
.ops = &dummy_ops,
|
.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;
|
static struct platform_device *dummy_pdev;
|
||||||
|
|
||||||
void __init regulator_dummy_init(void)
|
void __init regulator_dummy_init(void)
|
||||||
|
@ -55,12 +78,9 @@ void __init regulator_dummy_init(void)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
dummy_regulator_rdev = regulator_register(&dummy_desc, NULL,
|
ret = platform_driver_register(&dummy_regulator_driver);
|
||||||
&dummy_initdata, NULL);
|
if (ret != 0) {
|
||||||
if (IS_ERR(dummy_regulator_rdev)) {
|
pr_err("Failed to register dummy regulator driver: %d\n", ret);
|
||||||
ret = PTR_ERR(dummy_regulator_rdev);
|
|
||||||
pr_err("Failed to register regulator: %d\n", ret);
|
|
||||||
platform_device_unregister(dummy_pdev);
|
platform_device_unregister(dummy_pdev);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,7 +49,6 @@
|
||||||
#define TPS65911_REG_LDO7 11
|
#define TPS65911_REG_LDO7 11
|
||||||
#define TPS65911_REG_LDO8 12
|
#define TPS65911_REG_LDO8 12
|
||||||
|
|
||||||
#define TPS65910_NUM_REGULATOR 13
|
|
||||||
#define TPS65910_SUPPLY_STATE_ENABLED 0x1
|
#define TPS65910_SUPPLY_STATE_ENABLED 0x1
|
||||||
|
|
||||||
/* supported VIO voltages in milivolts */
|
/* supported VIO voltages in milivolts */
|
||||||
|
@ -264,11 +263,12 @@ static struct tps_info tps65911_regs[] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct tps65910_reg {
|
struct tps65910_reg {
|
||||||
struct regulator_desc desc[TPS65910_NUM_REGULATOR];
|
struct regulator_desc *desc;
|
||||||
struct tps65910 *mfd;
|
struct tps65910 *mfd;
|
||||||
struct regulator_dev *rdev[TPS65910_NUM_REGULATOR];
|
struct regulator_dev **rdev;
|
||||||
struct tps_info *info[TPS65910_NUM_REGULATOR];
|
struct tps_info **info;
|
||||||
struct mutex mutex;
|
struct mutex mutex;
|
||||||
|
int num_regulators;
|
||||||
int mode;
|
int mode;
|
||||||
int (*get_ctrl_reg)(int);
|
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;
|
mult = (selector / VDD1_2_NUM_VOLTS) + 1;
|
||||||
volt = VDD1_2_MIN_VOLT +
|
volt = VDD1_2_MIN_VOLT +
|
||||||
(selector % VDD1_2_NUM_VOLTS) * VDD1_2_OFFSET;
|
(selector % VDD1_2_NUM_VOLTS) * VDD1_2_OFFSET;
|
||||||
|
break;
|
||||||
case TPS65911_REG_VDDCTRL:
|
case TPS65911_REG_VDDCTRL:
|
||||||
volt = VDDCTRL_MIN_VOLT + (selector * VDDCTRL_OFFSET);
|
volt = VDDCTRL_MIN_VOLT + (selector * VDDCTRL_OFFSET);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
BUG();
|
||||||
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return volt * 100 * mult;
|
return volt * 100 * mult;
|
||||||
|
@ -897,16 +902,42 @@ static __devinit int tps65910_probe(struct platform_device *pdev)
|
||||||
switch(tps65910_chip_id(tps65910)) {
|
switch(tps65910_chip_id(tps65910)) {
|
||||||
case TPS65910:
|
case TPS65910:
|
||||||
pmic->get_ctrl_reg = &tps65910_get_ctrl_register;
|
pmic->get_ctrl_reg = &tps65910_get_ctrl_register;
|
||||||
|
pmic->num_regulators = ARRAY_SIZE(tps65910_regs);
|
||||||
info = tps65910_regs;
|
info = tps65910_regs;
|
||||||
|
break;
|
||||||
case TPS65911:
|
case TPS65911:
|
||||||
pmic->get_ctrl_reg = &tps65911_get_ctrl_register;
|
pmic->get_ctrl_reg = &tps65911_get_ctrl_register;
|
||||||
|
pmic->num_regulators = ARRAY_SIZE(tps65911_regs);
|
||||||
info = tps65911_regs;
|
info = tps65911_regs;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
pr_err("Invalid tps chip version\n");
|
pr_err("Invalid tps chip version\n");
|
||||||
|
kfree(pmic);
|
||||||
return -ENODEV;
|
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 */
|
/* Register the regulators */
|
||||||
pmic->info[i] = info;
|
pmic->info[i] = info;
|
||||||
|
|
||||||
|
@ -938,7 +969,7 @@ static __devinit int tps65910_probe(struct platform_device *pdev)
|
||||||
"failed to register %s regulator\n",
|
"failed to register %s regulator\n",
|
||||||
pdev->name);
|
pdev->name);
|
||||||
err = PTR_ERR(rdev);
|
err = PTR_ERR(rdev);
|
||||||
goto err;
|
goto err_unregister_regulator;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Save regulator for cleanup */
|
/* Save regulator for cleanup */
|
||||||
|
@ -946,23 +977,31 @@ static __devinit int tps65910_probe(struct platform_device *pdev)
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err:
|
err_unregister_regulator:
|
||||||
while (--i >= 0)
|
while (--i >= 0)
|
||||||
regulator_unregister(pmic->rdev[i]);
|
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);
|
kfree(pmic);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __devexit tps65910_remove(struct platform_device *pdev)
|
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;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < TPS65910_NUM_REGULATOR; i++)
|
for (i = 0; i < pmic->num_regulators; i++)
|
||||||
regulator_unregister(tps65910_reg->rdev[i]);
|
regulator_unregister(pmic->rdev[i]);
|
||||||
|
|
||||||
kfree(tps65910_reg);
|
kfree(pmic->rdev);
|
||||||
|
kfree(pmic->info);
|
||||||
|
kfree(pmic->desc);
|
||||||
|
kfree(pmic);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -835,8 +835,8 @@ static struct regulator_ops twlsmps_ops = {
|
||||||
remap_conf) \
|
remap_conf) \
|
||||||
TWL_FIXED_LDO(label, offset, mVolts, num, turnon_delay, \
|
TWL_FIXED_LDO(label, offset, mVolts, num, turnon_delay, \
|
||||||
remap_conf, TWL4030, twl4030fixed_ops)
|
remap_conf, TWL4030, twl4030fixed_ops)
|
||||||
#define TWL6030_FIXED_LDO(label, offset, mVolts, num, turnon_delay) \
|
#define TWL6030_FIXED_LDO(label, offset, mVolts, turnon_delay) \
|
||||||
TWL_FIXED_LDO(label, offset, mVolts, num, turnon_delay, \
|
TWL_FIXED_LDO(label, offset, mVolts, 0x0, turnon_delay, \
|
||||||
0x0, TWL6030, twl6030fixed_ops)
|
0x0, TWL6030, twl6030fixed_ops)
|
||||||
|
|
||||||
#define TWL4030_ADJUSTABLE_LDO(label, offset, num, turnon_delay, remap_conf) { \
|
#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, \
|
.base = offset, \
|
||||||
.id = num, \
|
|
||||||
.min_mV = min_mVolts, \
|
.min_mV = min_mVolts, \
|
||||||
.max_mV = max_mVolts, \
|
.max_mV = max_mVolts, \
|
||||||
.desc = { \
|
.desc = { \
|
||||||
.name = #label, \
|
.name = #label, \
|
||||||
.id = TWL6030_REG_##label, \
|
.id = TWL6030_REG_##label, \
|
||||||
.n_voltages = (max_mVolts - min_mVolts)/100, \
|
.n_voltages = (max_mVolts - min_mVolts)/100 + 1, \
|
||||||
.ops = &twl6030ldo_ops, \
|
.ops = &twl6030ldo_ops, \
|
||||||
.type = REGULATOR_VOLTAGE, \
|
.type = REGULATOR_VOLTAGE, \
|
||||||
.owner = THIS_MODULE, \
|
.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, \
|
.base = offset, \
|
||||||
.id = num, \
|
|
||||||
.min_mV = min_mVolts, \
|
.min_mV = min_mVolts, \
|
||||||
.max_mV = max_mVolts, \
|
.max_mV = max_mVolts, \
|
||||||
.desc = { \
|
.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, \
|
.base = offset, \
|
||||||
.id = num, \
|
|
||||||
.delay = turnon_delay, \
|
.delay = turnon_delay, \
|
||||||
.desc = { \
|
.desc = { \
|
||||||
.name = #label, \
|
.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, \
|
.base = offset, \
|
||||||
.id = num, \
|
|
||||||
.min_mV = 600, \
|
.min_mV = 600, \
|
||||||
.max_mV = 2100, \
|
.max_mV = 2100, \
|
||||||
.desc = { \
|
.desc = { \
|
||||||
|
@ -961,32 +957,32 @@ static struct twlreg_info twl_regs[] = {
|
||||||
/* 6030 REG with base as PMC Slave Misc : 0x0030 */
|
/* 6030 REG with base as PMC Slave Misc : 0x0030 */
|
||||||
/* Turnon-delay and remap configuration values for 6030 are not
|
/* Turnon-delay and remap configuration values for 6030 are not
|
||||||
verified since the specification is not public */
|
verified since the specification is not public */
|
||||||
TWL6030_ADJUSTABLE_LDO(VAUX1_6030, 0x54, 1000, 3300, 1),
|
TWL6030_ADJUSTABLE_LDO(VAUX1_6030, 0x54, 1000, 3300),
|
||||||
TWL6030_ADJUSTABLE_LDO(VAUX2_6030, 0x58, 1000, 3300, 2),
|
TWL6030_ADJUSTABLE_LDO(VAUX2_6030, 0x58, 1000, 3300),
|
||||||
TWL6030_ADJUSTABLE_LDO(VAUX3_6030, 0x5c, 1000, 3300, 3),
|
TWL6030_ADJUSTABLE_LDO(VAUX3_6030, 0x5c, 1000, 3300),
|
||||||
TWL6030_ADJUSTABLE_LDO(VMMC, 0x68, 1000, 3300, 4),
|
TWL6030_ADJUSTABLE_LDO(VMMC, 0x68, 1000, 3300),
|
||||||
TWL6030_ADJUSTABLE_LDO(VPP, 0x6c, 1000, 3300, 5),
|
TWL6030_ADJUSTABLE_LDO(VPP, 0x6c, 1000, 3300),
|
||||||
TWL6030_ADJUSTABLE_LDO(VUSIM, 0x74, 1000, 3300, 7),
|
TWL6030_ADJUSTABLE_LDO(VUSIM, 0x74, 1000, 3300),
|
||||||
TWL6030_FIXED_LDO(VANA, 0x50, 2100, 15, 0),
|
TWL6030_FIXED_LDO(VANA, 0x50, 2100, 0),
|
||||||
TWL6030_FIXED_LDO(VCXIO, 0x60, 1800, 16, 0),
|
TWL6030_FIXED_LDO(VCXIO, 0x60, 1800, 0),
|
||||||
TWL6030_FIXED_LDO(VDAC, 0x64, 1800, 17, 0),
|
TWL6030_FIXED_LDO(VDAC, 0x64, 1800, 0),
|
||||||
TWL6030_FIXED_LDO(VUSB, 0x70, 3300, 18, 0),
|
TWL6030_FIXED_LDO(VUSB, 0x70, 3300, 0),
|
||||||
TWL6030_FIXED_RESOURCE(CLK32KG, 0x8C, 48, 0),
|
TWL6030_FIXED_RESOURCE(CLK32KG, 0x8C, 0),
|
||||||
|
|
||||||
/* 6025 are renamed compared to 6030 versions */
|
/* 6025 are renamed compared to 6030 versions */
|
||||||
TWL6025_ADJUSTABLE_LDO(LDO2, 0x54, 1000, 3300, 1),
|
TWL6025_ADJUSTABLE_LDO(LDO2, 0x54, 1000, 3300),
|
||||||
TWL6025_ADJUSTABLE_LDO(LDO4, 0x58, 1000, 3300, 2),
|
TWL6025_ADJUSTABLE_LDO(LDO4, 0x58, 1000, 3300),
|
||||||
TWL6025_ADJUSTABLE_LDO(LDO3, 0x5c, 1000, 3300, 3),
|
TWL6025_ADJUSTABLE_LDO(LDO3, 0x5c, 1000, 3300),
|
||||||
TWL6025_ADJUSTABLE_LDO(LDO5, 0x68, 1000, 3300, 4),
|
TWL6025_ADJUSTABLE_LDO(LDO5, 0x68, 1000, 3300),
|
||||||
TWL6025_ADJUSTABLE_LDO(LDO1, 0x6c, 1000, 3300, 5),
|
TWL6025_ADJUSTABLE_LDO(LDO1, 0x6c, 1000, 3300),
|
||||||
TWL6025_ADJUSTABLE_LDO(LDO7, 0x74, 1000, 3300, 7),
|
TWL6025_ADJUSTABLE_LDO(LDO7, 0x74, 1000, 3300),
|
||||||
TWL6025_ADJUSTABLE_LDO(LDO6, 0x60, 1000, 3300, 16),
|
TWL6025_ADJUSTABLE_LDO(LDO6, 0x60, 1000, 3300),
|
||||||
TWL6025_ADJUSTABLE_LDO(LDOLN, 0x64, 1000, 3300, 17),
|
TWL6025_ADJUSTABLE_LDO(LDOLN, 0x64, 1000, 3300),
|
||||||
TWL6025_ADJUSTABLE_LDO(LDOUSB, 0x70, 1000, 3300, 18),
|
TWL6025_ADJUSTABLE_LDO(LDOUSB, 0x70, 1000, 3300),
|
||||||
|
|
||||||
TWL6025_ADJUSTABLE_SMPS(SMPS3, 0x34, 1),
|
TWL6025_ADJUSTABLE_SMPS(SMPS3, 0x34),
|
||||||
TWL6025_ADJUSTABLE_SMPS(SMPS4, 0x10, 2),
|
TWL6025_ADJUSTABLE_SMPS(SMPS4, 0x10),
|
||||||
TWL6025_ADJUSTABLE_SMPS(VIO, 0x16, 3),
|
TWL6025_ADJUSTABLE_SMPS(VIO, 0x16),
|
||||||
};
|
};
|
||||||
|
|
||||||
static u8 twl_get_smps_offset(void)
|
static u8 twl_get_smps_offset(void)
|
||||||
|
|
|
@ -267,23 +267,6 @@ static int wm831x_buckv_select_min_voltage(struct regulator_dev *rdev,
|
||||||
return vsel;
|
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)
|
static int wm831x_buckv_set_dvs(struct regulator_dev *rdev, int state)
|
||||||
{
|
{
|
||||||
struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev);
|
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)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
/* Set the high voltage as the DVS voltage. This is optimised
|
/*
|
||||||
* for CPUfreq usage, most processors will keep the maximum
|
* If this VSEL is higher than the last one we've seen then
|
||||||
* voltage constant and lower the minimum with the frequency. */
|
* remember it as the DVS VSEL. This is optimised for CPUfreq
|
||||||
vsel = wm831x_buckv_select_max_voltage(rdev, min_uV, max_uV);
|
* usage where we want to get to the highest voltage very
|
||||||
if (vsel < 0) {
|
* quickly.
|
||||||
/* This should never happen - at worst the same vsel
|
*/
|
||||||
* should be chosen */
|
if (vsel > dcdc->dvs_vsel) {
|
||||||
WARN_ON(vsel < 0);
|
ret = wm831x_set_bits(wm831x, dvs_reg,
|
||||||
return 0;
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -456,27 +434,6 @@ static __devinit void wm831x_buckv_dvs_init(struct wm831x_dcdc *dcdc,
|
||||||
if (!pdata || !pdata->dvs_gpio)
|
if (!pdata || !pdata->dvs_gpio)
|
||||||
return;
|
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");
|
ret = gpio_request(pdata->dvs_gpio, "DCDC DVS");
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
dev_err(wm831x->dev, "Failed to get %s DVS GPIO: %d\n",
|
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;
|
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)
|
static __devinit int wm831x_buckv_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
|
struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
|
||||||
struct wm831x_pdata *pdata = wm831x->dev->platform_data;
|
struct wm831x_pdata *pdata = wm831x->dev->platform_data;
|
||||||
int id = pdev->id % ARRAY_SIZE(pdata->dcdc);
|
int id;
|
||||||
struct wm831x_dcdc *dcdc;
|
struct wm831x_dcdc *dcdc;
|
||||||
struct resource *res;
|
struct resource *res;
|
||||||
int ret, irq;
|
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);
|
dev_dbg(&pdev->dev, "Probing DCDC%d\n", id + 1);
|
||||||
|
|
||||||
if (pdata == NULL || pdata->dcdc[id] == NULL)
|
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;
|
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) {
|
if (ret < 0) {
|
||||||
dev_err(wm831x->dev, "Failed to read DVS VSEL: %d\n", ret);
|
dev_err(wm831x->dev, "Failed to read DVS VSEL: %d\n", ret);
|
||||||
goto err;
|
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 *wm831x = dev_get_drvdata(pdev->dev.parent);
|
||||||
struct wm831x_pdata *pdata = wm831x->dev->platform_data;
|
struct wm831x_pdata *pdata = wm831x->dev->platform_data;
|
||||||
int id = pdev->id % ARRAY_SIZE(pdata->dcdc);
|
int id;
|
||||||
struct wm831x_dcdc *dcdc;
|
struct wm831x_dcdc *dcdc;
|
||||||
struct resource *res;
|
struct resource *res;
|
||||||
int ret, irq;
|
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);
|
dev_dbg(&pdev->dev, "Probing DCDC%d\n", id + 1);
|
||||||
|
|
||||||
if (pdata == NULL || pdata->dcdc[id] == NULL)
|
if (pdata == NULL || pdata->dcdc[id] == NULL)
|
||||||
|
@ -1046,3 +1049,4 @@ MODULE_DESCRIPTION("WM831x DC-DC convertor driver");
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
MODULE_ALIAS("platform:wm831x-buckv");
|
MODULE_ALIAS("platform:wm831x-buckv");
|
||||||
MODULE_ALIAS("platform:wm831x-buckp");
|
MODULE_ALIAS("platform:wm831x-buckp");
|
||||||
|
MODULE_ALIAS("platform:wm831x-epe");
|
||||||
|
|
|
@ -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 *wm831x = dev_get_drvdata(pdev->dev.parent);
|
||||||
struct wm831x_pdata *pdata = wm831x->dev->platform_data;
|
struct wm831x_pdata *pdata = wm831x->dev->platform_data;
|
||||||
int id = pdev->id % ARRAY_SIZE(pdata->ldo);
|
int id;
|
||||||
struct wm831x_ldo *ldo;
|
struct wm831x_ldo *ldo;
|
||||||
struct resource *res;
|
struct resource *res;
|
||||||
int ret, irq;
|
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);
|
dev_dbg(&pdev->dev, "Probing LDO%d\n", id + 1);
|
||||||
|
|
||||||
if (pdata == NULL || pdata->ldo[id] == NULL)
|
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 *wm831x = dev_get_drvdata(pdev->dev.parent);
|
||||||
struct wm831x_pdata *pdata = wm831x->dev->platform_data;
|
struct wm831x_pdata *pdata = wm831x->dev->platform_data;
|
||||||
int id = pdev->id % ARRAY_SIZE(pdata->ldo);
|
int id;
|
||||||
struct wm831x_ldo *ldo;
|
struct wm831x_ldo *ldo;
|
||||||
struct resource *res;
|
struct resource *res;
|
||||||
int ret, irq;
|
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);
|
dev_dbg(&pdev->dev, "Probing LDO%d\n", id + 1);
|
||||||
|
|
||||||
if (pdata == NULL || pdata->ldo[id] == NULL)
|
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 *wm831x = dev_get_drvdata(pdev->dev.parent);
|
||||||
struct wm831x_pdata *pdata = wm831x->dev->platform_data;
|
struct wm831x_pdata *pdata = wm831x->dev->platform_data;
|
||||||
int id = pdev->id % ARRAY_SIZE(pdata->ldo);
|
int id;
|
||||||
struct wm831x_ldo *ldo;
|
struct wm831x_ldo *ldo;
|
||||||
struct resource *res;
|
struct resource *res;
|
||||||
int ret;
|
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);
|
dev_dbg(&pdev->dev, "Probing LDO%d\n", id + 1);
|
||||||
|
|
||||||
if (pdata == NULL || pdata->ldo[id] == NULL)
|
if (pdata == NULL || pdata->ldo[id] == NULL)
|
||||||
|
|
|
@ -43,7 +43,7 @@ static int wm8994_ldo_enable(struct regulator_dev *rdev)
|
||||||
if (!ldo->enable)
|
if (!ldo->enable)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
gpio_set_value(ldo->enable, 1);
|
gpio_set_value_cansleep(ldo->enable, 1);
|
||||||
ldo->is_enabled = true;
|
ldo->is_enabled = true;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -57,7 +57,7 @@ static int wm8994_ldo_disable(struct regulator_dev *rdev)
|
||||||
if (!ldo->enable)
|
if (!ldo->enable)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
gpio_set_value(ldo->enable, 0);
|
gpio_set_value_cansleep(ldo->enable, 0);
|
||||||
ldo->is_enabled = false;
|
ldo->is_enabled = false;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -122,6 +122,9 @@ struct regulator;
|
||||||
struct regulator_bulk_data {
|
struct regulator_bulk_data {
|
||||||
const char *supply;
|
const char *supply;
|
||||||
struct regulator *consumer;
|
struct regulator *consumer;
|
||||||
|
|
||||||
|
/* Internal use */
|
||||||
|
int ret;
|
||||||
};
|
};
|
||||||
|
|
||||||
#if defined(CONFIG_REGULATOR)
|
#if defined(CONFIG_REGULATOR)
|
||||||
|
|
|
@ -188,18 +188,16 @@ struct regulator_dev {
|
||||||
|
|
||||||
/* lists we belong to */
|
/* lists we belong to */
|
||||||
struct list_head list; /* list of all regulators */
|
struct list_head list; /* list of all regulators */
|
||||||
struct list_head slist; /* list of supplied regulators */
|
|
||||||
|
|
||||||
/* lists we own */
|
/* lists we own */
|
||||||
struct list_head consumer_list; /* consumers we supply */
|
struct list_head consumer_list; /* consumers we supply */
|
||||||
struct list_head supply_list; /* regulators we supply */
|
|
||||||
|
|
||||||
struct blocking_notifier_head notifier;
|
struct blocking_notifier_head notifier;
|
||||||
struct mutex mutex; /* consumer lock */
|
struct mutex mutex; /* consumer lock */
|
||||||
struct module *owner;
|
struct module *owner;
|
||||||
struct device dev;
|
struct device dev;
|
||||||
struct regulation_constraints *constraints;
|
struct regulation_constraints *constraints;
|
||||||
struct regulator_dev *supply; /* for tree */
|
struct regulator *supply; /* for tree */
|
||||||
|
|
||||||
void *reg_data; /* regulator_dev data */
|
void *reg_data; /* regulator_dev data */
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue