Initial Contribution

msm-2.6.38: tag AU_LINUX_ANDROID_GINGERBREAD.02.03.04.00.142

Signed-off-by: Bryan Huntsman <bryanh@codeaurora.org>
This commit is contained in:
Bryan Huntsman
2011-08-16 17:27:22 -07:00
parent f06154cc47
commit 3f2bc4d6eb
1851 changed files with 780136 additions and 12902 deletions

View File

@@ -24,6 +24,9 @@
#include <linux/mutex.h>
#include <linux/suspend.h>
#include <linux/delay.h>
#include <linux/debugfs.h>
#include <linux/seq_file.h>
#include <linux/uaccess.h>
#include <linux/regulator/consumer.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
@@ -47,6 +50,7 @@ static LIST_HEAD(regulator_list);
static LIST_HEAD(regulator_map_list);
static bool has_full_constraints;
static bool board_wants_dummy_regulator;
static int suppress_info_printing;
#ifdef CONFIG_DEBUG_FS
static struct dentry *debugfs_root;
@@ -75,6 +79,7 @@ struct regulator {
int uA_load;
int min_uV;
int max_uV;
int enabled;
char *supply_name;
struct device_attribute dev_attr;
struct regulator_dev *rdev;
@@ -138,6 +143,15 @@ static int regulator_check_voltage(struct regulator_dev *rdev,
return -EPERM;
}
/* check if requested voltage range actually overlaps the constraints */
if (*max_uV < rdev->constraints->min_uV ||
*min_uV > rdev->constraints->max_uV) {
rdev_err(rdev, "requested voltage range [%d, %d] does not fit "
"within constraints: [%d, %d]\n", *min_uV, *max_uV,
rdev->constraints->min_uV, rdev->constraints->max_uV);
return -EINVAL;
}
if (*max_uV > rdev->constraints->max_uV)
*max_uV = rdev->constraints->max_uV;
if (*min_uV < rdev->constraints->min_uV)
@@ -587,13 +601,87 @@ static struct class regulator_class = {
.dev_attrs = regulator_dev_attrs,
};
static int regulator_check_voltage_update(struct regulator_dev *rdev)
{
if (!rdev->constraints)
return -ENODEV;
if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_VOLTAGE))
return -EPERM;
if (!rdev->desc->ops->set_voltage)
return -EINVAL;
return 0;
}
static int update_voltage(struct regulator *regulator, int min_uV, int max_uV)
{
struct regulator_dev *rdev = regulator->rdev;
struct regulator *sibling;
int ret = 0;
list_for_each_entry(sibling, &rdev->consumer_list, list) {
if (regulator == sibling || !sibling->enabled)
continue;
if (max_uV < sibling->min_uV || min_uV > sibling->max_uV) {
printk(KERN_ERR "%s: requested voltage range [%d, %d] "
"for %s does not fit within previously voted "
"range: [%d, %d]\n",
__func__, min_uV, max_uV,
rdev_get_name(regulator->rdev),
sibling->min_uV,
sibling->max_uV);
ret = -EINVAL;
goto out;
}
if (sibling->max_uV < max_uV)
max_uV = sibling->max_uV;
if (sibling->min_uV > min_uV)
min_uV = sibling->min_uV;
}
ret = _regulator_do_set_voltage(rdev, min_uV, max_uV);
if (!ret)
goto out;
_notifier_call_chain(rdev, REGULATOR_EVENT_VOLTAGE_CHANGE, NULL);
out:
return ret;
}
static int update_voltage_prev(struct regulator_dev *rdev)
{
int ret, min_uV = INT_MIN, max_uV = INT_MAX;
struct regulator *consumer;
list_for_each_entry(consumer, &rdev->consumer_list, list) {
if (!consumer->enabled)
continue;
if (consumer->max_uV < max_uV)
max_uV = consumer->max_uV;
if (consumer->min_uV > min_uV)
min_uV = consumer->min_uV;
}
if (min_uV == INT_MIN)
return 0;
ret = _regulator_do_set_voltage(rdev, min_uV, max_uV);
if (!ret)
return ret;
_notifier_call_chain(rdev, REGULATOR_EVENT_VOLTAGE_CHANGE, NULL);
return ret;
}
/* Calculate the new optimum regulator operating mode based on the new total
* consumer load. All locks held by caller */
static void drms_uA_update(struct regulator_dev *rdev)
{
struct regulator *sibling;
int current_uA = 0, output_uV, input_uV, err;
unsigned int mode;
unsigned int regulator_curr_mode, mode;
err = regulator_check_drms(rdev);
if (err < 0 || !rdev->desc->ops->get_optimum_mode ||
@@ -626,6 +714,14 @@ static void drms_uA_update(struct regulator_dev *rdev)
/* check the new mode is allowed */
err = regulator_mode_constrain(rdev, &mode);
/* return if the same mode is requested */
if (rdev->desc->ops->get_mode) {
regulator_curr_mode = rdev->desc->ops->get_mode(rdev);
if (regulator_curr_mode == mode)
return;
} else
return;
if (err == 0)
rdev->desc->ops->set_mode(rdev, mode);
}
@@ -914,7 +1010,8 @@ static int set_machine_constraints(struct regulator_dev *rdev,
}
}
print_constraints(rdev);
if (!suppress_info_printing)
print_constraints(rdev);
out:
return ret;
}
@@ -1389,7 +1486,33 @@ int regulator_enable(struct regulator *regulator)
int ret = 0;
mutex_lock(&rdev->mutex);
if (!regulator_check_voltage_update(rdev)) {
if (regulator->min_uV < rdev->constraints->min_uV ||
regulator->max_uV > rdev->constraints->max_uV) {
rdev_err(rdev, "invalid input - constraint: [%d, %d], "
"set point: [%d, %d]\n",
rdev->constraints->min_uV,
rdev->constraints->max_uV,
regulator->min_uV,
regulator->max_uV);
ret = -EINVAL;
goto out;
}
ret = update_voltage(regulator, regulator->min_uV,
regulator->max_uV);
if (ret)
goto out;
}
ret = _regulator_enable(rdev);
if (ret)
goto out;
regulator->enabled++;
out:
mutex_unlock(&rdev->mutex);
return ret;
}
@@ -1463,6 +1586,15 @@ int regulator_disable(struct regulator *regulator)
mutex_lock(&rdev->mutex);
ret = _regulator_disable(rdev, &supply_rdev);
if (ret)
goto out;
regulator->enabled--;
if (!regulator_check_voltage_update(rdev))
update_voltage_prev(rdev);
out:
mutex_unlock(&rdev->mutex);
/* decrease our supplies ref count and disable if required */
@@ -1770,15 +1902,16 @@ int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV)
ret = regulator_check_voltage(rdev, &min_uV, &max_uV);
if (ret < 0)
goto out;
if (regulator->enabled) {
ret = update_voltage(regulator, min_uV, max_uV);
if (ret)
goto out;
}
regulator->min_uV = min_uV;
regulator->max_uV = max_uV;
ret = regulator_check_consumers(rdev, &min_uV, &max_uV);
if (ret < 0)
goto out;
ret = _regulator_do_set_voltage(rdev, min_uV, max_uV);
out:
mutex_unlock(&rdev->mutex);
return ret;
@@ -2514,22 +2647,356 @@ static int add_regulator_attributes(struct regulator_dev *rdev)
return status;
}
#ifdef CONFIG_DEBUG_FS
#define MAX_DEBUG_BUF_LEN 50
static DEFINE_MUTEX(debug_buf_mutex);
static char debug_buf[MAX_DEBUG_BUF_LEN];
static int reg_debug_enable_set(void *data, u64 val)
{
int err_info;
if (IS_ERR(data) || data == NULL) {
pr_err("Function Input Error %ld\n", PTR_ERR(data));
return -ENOMEM;
}
if (val)
err_info = regulator_enable(data);
else
err_info = regulator_disable(data);
return err_info;
}
static int reg_debug_enable_get(void *data, u64 *val)
{
if (IS_ERR(data) || data == NULL) {
pr_err("Function Input Error %ld\n", PTR_ERR(data));
return -ENOMEM;
}
*val = regulator_is_enabled(data);
return 0;
}
DEFINE_SIMPLE_ATTRIBUTE(reg_enable_fops, reg_debug_enable_get,
reg_debug_enable_set, "%llu\n");
static int reg_debug_fdisable_set(void *data, u64 val)
{
int err_info;
if (IS_ERR(data) || data == NULL) {
pr_err("Function Input Error %ld\n", PTR_ERR(data));
return -ENOMEM;
}
if (val > 0)
err_info = regulator_force_disable(data);
else
err_info = 0;
return err_info;
}
DEFINE_SIMPLE_ATTRIBUTE(reg_fdisable_fops, reg_debug_enable_get,
reg_debug_fdisable_set, "%llu\n");
static ssize_t reg_debug_volt_set(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
int err_info, filled;
int min, max = -1;
if (IS_ERR(file) || file == NULL) {
pr_err("Function Input Error %ld\n", PTR_ERR(file));
return -ENOMEM;
}
if (count < MAX_DEBUG_BUF_LEN) {
mutex_lock(&debug_buf_mutex);
if (copy_from_user(debug_buf, (void __user *) buf, count))
return -EFAULT;
debug_buf[count] = '\0';
filled = sscanf(debug_buf, "%d %d", &min, &max);
mutex_unlock(&debug_buf_mutex);
/* check that user entered two numbers */
if (filled < 2 || min < 0 || max < min) {
pr_info("Error, correct format: 'echo \"min max\""
" > voltage");
return -ENOMEM;
} else {
err_info = regulator_set_voltage(file->private_data,
min, max);
}
} else {
pr_err("Error-Input voltage pair"
" string exceeds maximum buffer length");
return -ENOMEM;
}
return count;
}
static ssize_t reg_debug_volt_get(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
int voltage, output, rc;
if (IS_ERR(file) || file == NULL) {
pr_err("Function Input Error %ld\n", PTR_ERR(file));
return -ENOMEM;
}
voltage = regulator_get_voltage(file->private_data);
mutex_lock(&debug_buf_mutex);
output = snprintf(debug_buf, MAX_DEBUG_BUF_LEN-1, "%d\n", voltage);
rc = simple_read_from_buffer((void __user *) buf, output, ppos,
(void *) debug_buf, output);
mutex_unlock(&debug_buf_mutex);
return rc;
}
static int reg_debug_volt_open(struct inode *inode, struct file *file)
{
if (IS_ERR(file) || file == NULL) {
pr_err("Function Input Error %ld\n", PTR_ERR(file));
return -ENOMEM;
}
file->private_data = inode->i_private;
return 0;
}
static const struct file_operations reg_volt_fops = {
.write = reg_debug_volt_set,
.open = reg_debug_volt_open,
.read = reg_debug_volt_get,
};
static int reg_debug_mode_set(void *data, u64 val)
{
int err_info;
if (IS_ERR(data) || data == NULL) {
pr_err("Function Input Error %ld\n", PTR_ERR(data));
return -ENOMEM;
}
err_info = regulator_set_mode(data, (unsigned int)val);
return err_info;
}
static int reg_debug_mode_get(void *data, u64 *val)
{
int err_info;
if (IS_ERR(data) || data == NULL) {
pr_err("Function Input Error %ld\n", PTR_ERR(data));
return -ENOMEM;
}
err_info = regulator_get_mode(data);
if (err_info < 0) {
pr_err("Regulator_get_mode returned an error!\n");
return -ENOMEM;
} else {
*val = err_info;
return 0;
}
}
DEFINE_SIMPLE_ATTRIBUTE(reg_mode_fops, reg_debug_mode_get,
reg_debug_mode_set, "%llu\n");
static int reg_debug_optimum_mode_set(void *data, u64 val)
{
int err_info;
if (IS_ERR(data) || data == NULL) {
pr_err("Function Input Error %ld\n", PTR_ERR(data));
return -ENOMEM;
}
err_info = regulator_set_optimum_mode(data, (unsigned int)val);
if (err_info < 0) {
pr_err("Regulator_set_optimum_mode returned an error!\n");
return err_info;
}
return 0;
}
DEFINE_SIMPLE_ATTRIBUTE(reg_optimum_mode_fops, reg_debug_mode_get,
reg_debug_optimum_mode_set, "%llu\n");
static int reg_debug_consumers_show(struct seq_file *m, void *v)
{
struct regulator_dev *rdev = m->private;
struct regulator *reg;
char *supply_name;
if (!rdev) {
pr_err("regulator device missing");
return -EINVAL;
}
mutex_lock(&rdev->mutex);
/* Print a header if there are consumers. */
if (rdev->open_count)
seq_printf(m, "Device-Supply "
"EN Min_uV Max_uV load_uA\n");
list_for_each_entry(reg, &rdev->consumer_list, list) {
if (reg->supply_name)
supply_name = reg->supply_name;
else
supply_name = "(null)-(null)";
seq_printf(m, "%-32s %c %8d %8d %8d\n", supply_name,
(reg->enabled ? 'Y' : 'N'), reg->min_uV, reg->max_uV,
reg->uA_load);
}
mutex_unlock(&rdev->mutex);
return 0;
}
static int reg_debug_consumers_open(struct inode *inode, struct file *file)
{
return single_open(file, reg_debug_consumers_show, inode->i_private);
}
static const struct file_operations reg_consumers_fops = {
.owner = THIS_MODULE,
.open = reg_debug_consumers_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
static void rdev_init_debugfs(struct regulator_dev *rdev)
{
#ifdef CONFIG_DEBUG_FS
struct dentry *err_ptr = NULL;
struct regulator *reg;
struct regulator_ops *reg_ops;
mode_t mode;
if (IS_ERR(rdev) || rdev == NULL ||
IS_ERR(debugfs_root) || debugfs_root == NULL) {
pr_err("Error-Bad Function Input\n");
goto error;
}
rdev->debugfs = debugfs_create_dir(rdev_get_name(rdev), debugfs_root);
if (IS_ERR(rdev->debugfs) || !rdev->debugfs) {
rdev_warn(rdev, "Failed to create debugfs directory\n");
rdev->debugfs = NULL;
return;
goto error;
}
debugfs_create_u32("use_count", 0444, rdev->debugfs,
&rdev->use_count);
debugfs_create_u32("open_count", 0444, rdev->debugfs,
&rdev->open_count);
#endif
debugfs_create_file("consumers", 0444, rdev->debugfs, rdev,
&reg_consumers_fops);
reg = regulator_get(NULL, rdev->desc->name);
if (IS_ERR(reg) || reg == NULL) {
pr_err("Error-Bad Function Input\n");
goto error;
}
reg_ops = rdev->desc->ops;
mode = S_IRUGO | S_IWUSR;
/* Enabled File */
if (mode)
err_ptr = debugfs_create_file("enable", mode, rdev->debugfs,
reg, &reg_enable_fops);
if (IS_ERR(err_ptr)) {
pr_err("Error-Could not create enable file\n");
debugfs_remove_recursive(rdev->debugfs);
goto error;
}
mode = 0;
/* Force-Disable File */
if (reg_ops->is_enabled)
mode |= S_IRUGO;
if (reg_ops->enable || reg_ops->disable)
mode |= S_IWUSR;
if (mode)
err_ptr = debugfs_create_file("force_disable", mode,
rdev->debugfs, reg, &reg_fdisable_fops);
if (IS_ERR(err_ptr)) {
pr_err("Error-Could not create force_disable file\n");
debugfs_remove_recursive(rdev->debugfs);
goto error;
}
mode = 0;
/* Voltage File */
if (reg_ops->get_voltage)
mode |= S_IRUGO;
if (reg_ops->set_voltage)
mode |= S_IWUSR;
if (mode)
err_ptr = debugfs_create_file("voltage", mode, rdev->debugfs,
reg, &reg_volt_fops);
if (IS_ERR(err_ptr)) {
pr_err("Error-Could not create voltage file\n");
debugfs_remove_recursive(rdev->debugfs);
goto error;
}
mode = 0;
/* Mode File */
if (reg_ops->get_mode)
mode |= S_IRUGO;
if (reg_ops->set_mode)
mode |= S_IWUSR;
if (mode)
err_ptr = debugfs_create_file("mode", mode, rdev->debugfs,
reg, &reg_mode_fops);
if (IS_ERR(err_ptr)) {
pr_err("Error-Could not create mode file\n");
debugfs_remove_recursive(rdev->debugfs);
goto error;
}
mode = 0;
/* Optimum Mode File */
if (reg_ops->get_mode)
mode |= S_IRUGO;
if (reg_ops->set_mode)
mode |= S_IWUSR;
if (mode)
err_ptr = debugfs_create_file("optimum_mode", mode,
rdev->debugfs, reg, &reg_optimum_mode_fops);
if (IS_ERR(err_ptr)) {
pr_err("Error-Could not create optimum_mode file\n");
debugfs_remove_recursive(rdev->debugfs);
goto error;
}
error:
return;
}
#else
static inline void rdev_init_debugfs(struct regulator_dev *rdev)
{
return;
}
#endif
/**
* regulator_register - register regulator
@@ -2663,9 +3130,9 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc,
list_add(&rdev->list, &regulator_list);
rdev_init_debugfs(rdev);
out:
mutex_unlock(&regulator_list_mutex);
rdev_init_debugfs(rdev);
return rdev;
unset_supplies:
@@ -2818,6 +3285,22 @@ void regulator_use_dummy_regulator(void)
}
EXPORT_SYMBOL_GPL(regulator_use_dummy_regulator);
/**
* regulator_suppress_info_printing - disable printing of info messages
*
* The regulator framework calls print_constraints() when a regulator is
* registered. It also prints a disable message for each unused regulator in
* regulator_init_complete().
*
* Calling this function ensures that such messages do not end up in the
* log.
*/
void regulator_suppress_info_printing(void)
{
suppress_info_printing = 1;
}
EXPORT_SYMBOL_GPL(regulator_suppress_info_printing);
/**
* rdev_get_drvdata - get rdev regulator driver data
* @rdev: regulator
@@ -2936,7 +3419,8 @@ static int __init regulator_init_complete(void)
if (has_full_constraints) {
/* We log since this may kill the system if it
* goes wrong. */
rdev_info(rdev, "disabling\n");
if (!suppress_info_printing)
rdev_info(rdev, "disabling\n");
ret = ops->disable(rdev);
if (ret != 0) {
rdev_err(rdev, "couldn't disable: %d\n", ret);
@@ -2947,7 +3431,9 @@ static int __init regulator_init_complete(void)
* so warn even if we aren't going to do
* anything here.
*/
rdev_warn(rdev, "incomplete constraints, leaving on\n");
if (!suppress_info_printing)
rdev_warn(rdev, "incomplete constraints, "
"leaving on\n");
}
unlock: