diff options
author | Osvaldo Banuelos <osvaldob@codeaurora.org> | 2014-12-16 17:16:25 -0800 |
---|---|---|
committer | Rohit Vaswani <rvaswani@codeaurora.org> | 2016-03-01 12:22:36 -0800 |
commit | db58e9bdc318201eca4eb5a457a6d4ea8d1857b5 (patch) | |
tree | dc3514a6a440930fd9c01002bfabbe3295068736 /drivers/regulator | |
parent | 9a5aec1c9268ffe4c857c5298bf43a0ddb9553d7 (diff) |
regulator: core: fix regulator bypass logic
Since the regulator debugfs consumer does not call
regulator_allow_bypass() on its regulator handles, regulators
will not be placed on bypass mode even if all other consumers
request for this. Fix this by introducing an open offset count
that can be used to selectively disregard the debugfs consumer.
Also, introduce a debugfs file to allow or disallow bypass
mode on each regulator by leveraging on the new open offset count.
Change-Id: If12534dac5e6b1c82acac9b5250137b4f816b922
Signed-off-by: Osvaldo Banuelos <osvaldob@codeaurora.org>
Diffstat (limited to 'drivers/regulator')
-rw-r--r-- | drivers/regulator/core.c | 62 |
1 files changed, 60 insertions, 2 deletions
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index bcc81c0d94fd..803bd385c01a 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -3398,7 +3398,8 @@ int regulator_allow_bypass(struct regulator *regulator, bool enable) if (enable && !regulator->bypass) { rdev->bypass_count++; - if (rdev->bypass_count == rdev->open_count) { + if (rdev->bypass_count == rdev->open_count - + rdev->open_offset) { ret = rdev->desc->ops->set_bypass(rdev, enable); if (ret != 0) rdev->bypass_count--; @@ -3407,7 +3408,8 @@ int regulator_allow_bypass(struct regulator *regulator, bool enable) } else if (!enable && regulator->bypass) { rdev->bypass_count--; - if (rdev->bypass_count != rdev->open_count) { + if (rdev->bypass_count != rdev->open_count - + rdev->open_offset) { ret = rdev->desc->ops->set_bypass(rdev, enable); if (ret != 0) rdev->bypass_count++; @@ -3908,6 +3910,46 @@ static int reg_debug_enable_get(void *data, u64 *val) DEFINE_SIMPLE_ATTRIBUTE(reg_enable_fops, reg_debug_enable_get, reg_debug_enable_set, "%llu\n"); +static int reg_debug_bypass_enable_get(void *data, u64 *val) +{ + struct regulator *regulator = data; + struct regulator_dev *rdev = regulator->rdev; + bool enable = false; + int rc = 0; + + mutex_lock(&rdev->mutex); + if (rdev->desc->ops->get_bypass) { + rc = rdev->desc->ops->get_bypass(rdev, &enable); + if (rc) + pr_err("get_bypass() failed, rc=%d\n", rc); + } else { + enable = (rdev->bypass_count == rdev->open_count + - rdev->open_offset); + } + mutex_unlock(&rdev->mutex); + + *val = enable; + + return rc; +} + +static int reg_debug_bypass_enable_set(void *data, u64 val) +{ + struct regulator *regulator = data; + struct regulator_dev *rdev = regulator->rdev; + int ret = 0; + + mutex_lock(&rdev->mutex); + rdev->open_offset = 0; + mutex_unlock(&rdev->mutex); + + ret = regulator_allow_bypass(data, val); + + return ret; +} +DEFINE_SIMPLE_ATTRIBUTE(reg_bypass_enable_fops, reg_debug_bypass_enable_get, + reg_debug_bypass_enable_set, "%llu\n"); + static int reg_debug_fdisable_set(void *data, u64 val) { int err_info; @@ -4152,6 +4194,7 @@ static void rdev_init_debugfs(struct regulator_dev *rdev) goto error; } + rdev->open_offset = 1; reg_ops = rdev->desc->ops; mode = S_IRUGO | S_IWUSR; /* Enabled File */ @@ -4165,6 +4208,21 @@ static void rdev_init_debugfs(struct regulator_dev *rdev) } mode = 0; + /* Bypass Enable File */ + if (reg_ops->set_bypass) + mode = S_IWUSR | S_IRUGO; + + if (mode) + err_ptr = debugfs_create_file("bypass", mode, + rdev->debugfs, reg, + ®_bypass_enable_fops); + if (IS_ERR(err_ptr)) { + pr_err("Error-Could not create bypass enable file\n"); + debugfs_remove_recursive(rdev->debugfs); + goto error; + } + + mode = 0; /* Force-Disable File */ if (reg_ops->is_enabled) mode |= S_IRUGO; |