Loading drivers/regulator/core.c +340 −3 Original line number Diff line number Diff line Loading @@ -27,6 +27,8 @@ #include <linux/gpio/consumer.h> #include <linux/of.h> #include <linux/regmap.h> #include <linux/seq_file.h> #include <linux/uaccess.h> #include <linux/regulator/of_regulator.h> #include <linux/regulator/consumer.h> #include <linux/regulator/driver.h> Loading Loading @@ -2283,7 +2285,11 @@ int regulator_enable(struct regulator *regulator) } mutex_lock(&rdev->mutex); ret = _regulator_enable(rdev); if (ret == 0) regulator->enabled++; mutex_unlock(&rdev->mutex); if (ret != 0 && rdev->supply) Loading Loading @@ -2392,6 +2398,8 @@ int regulator_disable(struct regulator *regulator) mutex_lock(&rdev->mutex); ret = _regulator_disable(rdev); if (ret == 0) regulator->enabled--; mutex_unlock(&rdev->mutex); if (ret == 0 && rdev->supply) Loading Loading @@ -3679,7 +3687,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--; Loading @@ -3688,7 +3697,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++; Loading Loading @@ -4106,11 +4116,271 @@ static void regulator_dev_release(struct device *dev) kfree(rdev); } #ifdef CONFIG_DEBUG_FS static int reg_debug_enable_set(void *data, u64 val) { struct regulator *regulator = data; int ret; if (val) { ret = regulator_enable(regulator); if (ret) rdev_err(regulator->rdev, "enable failed, ret=%d\n", ret); } else { ret = regulator_disable(regulator); if (ret) rdev_err(regulator->rdev, "disable failed, ret=%d\n", ret); } return ret; } static int reg_debug_enable_get(void *data, u64 *val) { struct regulator *regulator = data; *val = regulator_is_enabled(regulator); return 0; } 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 ret = 0; mutex_lock(&rdev->mutex); if (rdev->desc->ops->get_bypass) { ret = rdev->desc->ops->get_bypass(rdev, &enable); if (ret) rdev_err(rdev, "get_bypass() failed, ret=%d\n", ret); } else { enable = (rdev->bypass_count == rdev->open_count - rdev->open_offset); } mutex_unlock(&rdev->mutex); *val = enable; return ret; } 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_force_disable_set(void *data, u64 val) { struct regulator *regulator = data; int ret = 0; if (val > 0) { ret = regulator_force_disable(regulator); if (ret) rdev_err(regulator->rdev, "force_disable failed, ret=%d\n", ret); } return ret; } DEFINE_SIMPLE_ATTRIBUTE(reg_force_disable_fops, reg_debug_enable_get, reg_debug_force_disable_set, "%llu\n"); #define MAX_DEBUG_BUF_LEN 50 static ssize_t reg_debug_voltage_write(struct file *file, const char __user *ubuf, size_t count, loff_t *ppos) { struct regulator *regulator = file->private_data; char buf[MAX_DEBUG_BUF_LEN]; int ret, filled; int min_uV, max_uV = -1; if (count < MAX_DEBUG_BUF_LEN) { if (copy_from_user(buf, ubuf, count)) return -EFAULT; buf[count] = '\0'; filled = sscanf(buf, "%d %d", &min_uV, &max_uV); /* Check that both min and max voltage were specified. */ if (filled < 2 || min_uV < 0 || max_uV < min_uV) { rdev_err(regulator->rdev, "incorrect values specified: \"%s\"; should be: \"min_uV max_uV\"\n", buf); return -EINVAL; } ret = regulator_set_voltage(regulator, min_uV, max_uV); if (ret) { rdev_err(regulator->rdev, "set voltage(%d, %d) failed, ret=%d\n", min_uV, max_uV, ret); return ret; } } else { rdev_err(regulator->rdev, "voltage request string exceeds maximum buffer size\n"); return -EINVAL; } return count; } static ssize_t reg_debug_voltage_read(struct file *file, char __user *ubuf, size_t count, loff_t *ppos) { struct regulator *regulator = file->private_data; char buf[MAX_DEBUG_BUF_LEN]; int voltage, ret; voltage = regulator_get_voltage(regulator); ret = snprintf(buf, MAX_DEBUG_BUF_LEN - 1, "%d\n", voltage); return simple_read_from_buffer(ubuf, count, ppos, buf, ret); } static int reg_debug_voltage_open(struct inode *inode, struct file *file) { file->private_data = inode->i_private; return 0; } static const struct file_operations reg_voltage_fops = { .write = reg_debug_voltage_write, .open = reg_debug_voltage_open, .read = reg_debug_voltage_read, }; static int reg_debug_mode_set(void *data, u64 val) { struct regulator *regulator = data; unsigned int mode = val; int ret; ret = regulator_set_mode(regulator, mode); if (ret) rdev_err(regulator->rdev, "set mode=%u failed, ret=%d\n", mode, ret); return ret; } static int reg_debug_mode_get(void *data, u64 *val) { struct regulator *regulator = data; int mode; mode = regulator_get_mode(regulator); if (mode < 0) { rdev_err(regulator->rdev, "get mode failed, ret=%d\n", mode); return mode; } *val = mode; return 0; } DEFINE_SIMPLE_ATTRIBUTE(reg_mode_fops, reg_debug_mode_get, reg_debug_mode_set, "%llu\n"); static int reg_debug_set_load(void *data, u64 val) { struct regulator *regulator = data; int load = val; int ret; ret = regulator_set_load(regulator, load); if (ret) rdev_err(regulator->rdev, "set load=%d failed, ret=%d\n", load, ret); return ret; } DEFINE_SIMPLE_ATTRIBUTE(reg_set_load_fops, reg_debug_mode_get, reg_debug_set_load, "%llu\n"); static int reg_debug_consumers_show(struct seq_file *m, void *v) { struct regulator_dev *rdev = m->private; struct regulator *reg; const char *supply_name; mutex_lock(&rdev->mutex); /* Print a header if there are consumers. */ if (rdev->open_count) seq_printf(m, "%-32s EN Min_uV Max_uV load_uA\n", "Device-Supply"); 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->voltage[PM_SUSPEND_ON].min_uV, reg->voltage[PM_SUSPEND_ON].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_deinit_debugfs(struct regulator_dev *rdev) { if (!IS_ERR_OR_NULL(rdev)) { debugfs_remove_recursive(rdev->debugfs); if (rdev->debug_consumer) rdev->debug_consumer->debugfs = NULL; regulator_put(rdev->debug_consumer); } } static void rdev_init_debugfs(struct regulator_dev *rdev) { struct device *parent = rdev->dev.parent; const char *rname = rdev_get_name(rdev); char name[NAME_MAX]; struct regulator *regulator; const struct regulator_ops *ops; mode_t mode; /* Avoid duplicate debugfs directory names */ if (parent && rname == rdev->desc->name) { Loading @@ -4131,8 +4401,75 @@ static void rdev_init_debugfs(struct regulator_dev *rdev) &rdev->open_count); debugfs_create_u32("bypass_count", 0444, rdev->debugfs, &rdev->bypass_count); debugfs_create_file("consumers", 0444, rdev->debugfs, rdev, ®_consumers_fops); regulator = regulator_get(NULL, rdev_get_name(rdev)); if (IS_ERR(regulator)) { rdev_err(rdev, "regulator get failed, ret=%ld\n", PTR_ERR(regulator)); return; } rdev->debug_consumer = regulator; rdev->open_offset = 1; ops = rdev->desc->ops; debugfs_create_file("enable", 0644, rdev->debugfs, regulator, ®_enable_fops); if (ops->set_bypass) debugfs_create_file("bypass", 0644, rdev->debugfs, regulator, ®_bypass_enable_fops); mode = 0; if (ops->is_enabled) mode |= 0444; if (ops->disable) mode |= 0200; if (mode) debugfs_create_file("force_disable", mode, rdev->debugfs, regulator, ®_force_disable_fops); mode = 0; if (ops->get_voltage || ops->get_voltage_sel) mode |= 0444; if (ops->set_voltage || ops->set_voltage_sel) mode |= 0200; if (mode) debugfs_create_file("voltage", mode, rdev->debugfs, regulator, ®_voltage_fops); mode = 0; if (ops->get_mode) mode |= 0444; if (ops->set_mode) mode |= 0200; if (mode) debugfs_create_file("mode", mode, rdev->debugfs, regulator, ®_mode_fops); mode = 0; if (ops->get_mode) mode |= 0444; if (ops->set_load || (ops->get_optimum_mode && ops->set_mode)) mode |= 0200; if (mode) debugfs_create_file("load", mode, rdev->debugfs, regulator, ®_set_load_fops); } #else static inline void rdev_deinit_debugfs(struct regulator_dev *rdev) { } static inline void rdev_init_debugfs(struct regulator_dev *rdev) { } #endif static int regulator_register_resolve_supply(struct device *dev, void *data) { struct regulator_dev *rdev = dev_to_rdev(dev); Loading Loading @@ -4442,8 +4779,8 @@ void regulator_unregister(struct regulator_dev *rdev) regulator_disable(rdev->supply); regulator_put(rdev->supply); } rdev_deinit_debugfs(rdev); mutex_lock(®ulator_list_mutex); debugfs_remove_recursive(rdev->debugfs); flush_work(&rdev->disable_work.work); WARN_ON(rdev->open_count); unset_regulator_supplies(rdev); Loading drivers/regulator/internal.h +1 −0 Original line number Diff line number Diff line Loading @@ -43,6 +43,7 @@ struct regulator { unsigned int bypass:1; int uA_load; struct regulator_voltage voltage[REGULATOR_STATES_NUM]; int enabled; const char *supply_name; struct device_attribute dev_attr; struct regulator_dev *rdev; Loading include/linux/regulator/driver.h +2 −0 Original line number Diff line number Diff line Loading @@ -440,6 +440,7 @@ struct regulator_dev { int exclusive; u32 use_count; u32 open_count; u32 open_offset; u32 bypass_count; /* lists we belong to */ Loading Loading @@ -475,6 +476,7 @@ struct regulator_dev { /* time when this regulator was disabled last time */ unsigned long last_off_jiffy; struct regulator *debug_consumer; }; struct regulator_dev * Loading Loading
drivers/regulator/core.c +340 −3 Original line number Diff line number Diff line Loading @@ -27,6 +27,8 @@ #include <linux/gpio/consumer.h> #include <linux/of.h> #include <linux/regmap.h> #include <linux/seq_file.h> #include <linux/uaccess.h> #include <linux/regulator/of_regulator.h> #include <linux/regulator/consumer.h> #include <linux/regulator/driver.h> Loading Loading @@ -2283,7 +2285,11 @@ int regulator_enable(struct regulator *regulator) } mutex_lock(&rdev->mutex); ret = _regulator_enable(rdev); if (ret == 0) regulator->enabled++; mutex_unlock(&rdev->mutex); if (ret != 0 && rdev->supply) Loading Loading @@ -2392,6 +2398,8 @@ int regulator_disable(struct regulator *regulator) mutex_lock(&rdev->mutex); ret = _regulator_disable(rdev); if (ret == 0) regulator->enabled--; mutex_unlock(&rdev->mutex); if (ret == 0 && rdev->supply) Loading Loading @@ -3679,7 +3687,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--; Loading @@ -3688,7 +3697,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++; Loading Loading @@ -4106,11 +4116,271 @@ static void regulator_dev_release(struct device *dev) kfree(rdev); } #ifdef CONFIG_DEBUG_FS static int reg_debug_enable_set(void *data, u64 val) { struct regulator *regulator = data; int ret; if (val) { ret = regulator_enable(regulator); if (ret) rdev_err(regulator->rdev, "enable failed, ret=%d\n", ret); } else { ret = regulator_disable(regulator); if (ret) rdev_err(regulator->rdev, "disable failed, ret=%d\n", ret); } return ret; } static int reg_debug_enable_get(void *data, u64 *val) { struct regulator *regulator = data; *val = regulator_is_enabled(regulator); return 0; } 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 ret = 0; mutex_lock(&rdev->mutex); if (rdev->desc->ops->get_bypass) { ret = rdev->desc->ops->get_bypass(rdev, &enable); if (ret) rdev_err(rdev, "get_bypass() failed, ret=%d\n", ret); } else { enable = (rdev->bypass_count == rdev->open_count - rdev->open_offset); } mutex_unlock(&rdev->mutex); *val = enable; return ret; } 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_force_disable_set(void *data, u64 val) { struct regulator *regulator = data; int ret = 0; if (val > 0) { ret = regulator_force_disable(regulator); if (ret) rdev_err(regulator->rdev, "force_disable failed, ret=%d\n", ret); } return ret; } DEFINE_SIMPLE_ATTRIBUTE(reg_force_disable_fops, reg_debug_enable_get, reg_debug_force_disable_set, "%llu\n"); #define MAX_DEBUG_BUF_LEN 50 static ssize_t reg_debug_voltage_write(struct file *file, const char __user *ubuf, size_t count, loff_t *ppos) { struct regulator *regulator = file->private_data; char buf[MAX_DEBUG_BUF_LEN]; int ret, filled; int min_uV, max_uV = -1; if (count < MAX_DEBUG_BUF_LEN) { if (copy_from_user(buf, ubuf, count)) return -EFAULT; buf[count] = '\0'; filled = sscanf(buf, "%d %d", &min_uV, &max_uV); /* Check that both min and max voltage were specified. */ if (filled < 2 || min_uV < 0 || max_uV < min_uV) { rdev_err(regulator->rdev, "incorrect values specified: \"%s\"; should be: \"min_uV max_uV\"\n", buf); return -EINVAL; } ret = regulator_set_voltage(regulator, min_uV, max_uV); if (ret) { rdev_err(regulator->rdev, "set voltage(%d, %d) failed, ret=%d\n", min_uV, max_uV, ret); return ret; } } else { rdev_err(regulator->rdev, "voltage request string exceeds maximum buffer size\n"); return -EINVAL; } return count; } static ssize_t reg_debug_voltage_read(struct file *file, char __user *ubuf, size_t count, loff_t *ppos) { struct regulator *regulator = file->private_data; char buf[MAX_DEBUG_BUF_LEN]; int voltage, ret; voltage = regulator_get_voltage(regulator); ret = snprintf(buf, MAX_DEBUG_BUF_LEN - 1, "%d\n", voltage); return simple_read_from_buffer(ubuf, count, ppos, buf, ret); } static int reg_debug_voltage_open(struct inode *inode, struct file *file) { file->private_data = inode->i_private; return 0; } static const struct file_operations reg_voltage_fops = { .write = reg_debug_voltage_write, .open = reg_debug_voltage_open, .read = reg_debug_voltage_read, }; static int reg_debug_mode_set(void *data, u64 val) { struct regulator *regulator = data; unsigned int mode = val; int ret; ret = regulator_set_mode(regulator, mode); if (ret) rdev_err(regulator->rdev, "set mode=%u failed, ret=%d\n", mode, ret); return ret; } static int reg_debug_mode_get(void *data, u64 *val) { struct regulator *regulator = data; int mode; mode = regulator_get_mode(regulator); if (mode < 0) { rdev_err(regulator->rdev, "get mode failed, ret=%d\n", mode); return mode; } *val = mode; return 0; } DEFINE_SIMPLE_ATTRIBUTE(reg_mode_fops, reg_debug_mode_get, reg_debug_mode_set, "%llu\n"); static int reg_debug_set_load(void *data, u64 val) { struct regulator *regulator = data; int load = val; int ret; ret = regulator_set_load(regulator, load); if (ret) rdev_err(regulator->rdev, "set load=%d failed, ret=%d\n", load, ret); return ret; } DEFINE_SIMPLE_ATTRIBUTE(reg_set_load_fops, reg_debug_mode_get, reg_debug_set_load, "%llu\n"); static int reg_debug_consumers_show(struct seq_file *m, void *v) { struct regulator_dev *rdev = m->private; struct regulator *reg; const char *supply_name; mutex_lock(&rdev->mutex); /* Print a header if there are consumers. */ if (rdev->open_count) seq_printf(m, "%-32s EN Min_uV Max_uV load_uA\n", "Device-Supply"); 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->voltage[PM_SUSPEND_ON].min_uV, reg->voltage[PM_SUSPEND_ON].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_deinit_debugfs(struct regulator_dev *rdev) { if (!IS_ERR_OR_NULL(rdev)) { debugfs_remove_recursive(rdev->debugfs); if (rdev->debug_consumer) rdev->debug_consumer->debugfs = NULL; regulator_put(rdev->debug_consumer); } } static void rdev_init_debugfs(struct regulator_dev *rdev) { struct device *parent = rdev->dev.parent; const char *rname = rdev_get_name(rdev); char name[NAME_MAX]; struct regulator *regulator; const struct regulator_ops *ops; mode_t mode; /* Avoid duplicate debugfs directory names */ if (parent && rname == rdev->desc->name) { Loading @@ -4131,8 +4401,75 @@ static void rdev_init_debugfs(struct regulator_dev *rdev) &rdev->open_count); debugfs_create_u32("bypass_count", 0444, rdev->debugfs, &rdev->bypass_count); debugfs_create_file("consumers", 0444, rdev->debugfs, rdev, ®_consumers_fops); regulator = regulator_get(NULL, rdev_get_name(rdev)); if (IS_ERR(regulator)) { rdev_err(rdev, "regulator get failed, ret=%ld\n", PTR_ERR(regulator)); return; } rdev->debug_consumer = regulator; rdev->open_offset = 1; ops = rdev->desc->ops; debugfs_create_file("enable", 0644, rdev->debugfs, regulator, ®_enable_fops); if (ops->set_bypass) debugfs_create_file("bypass", 0644, rdev->debugfs, regulator, ®_bypass_enable_fops); mode = 0; if (ops->is_enabled) mode |= 0444; if (ops->disable) mode |= 0200; if (mode) debugfs_create_file("force_disable", mode, rdev->debugfs, regulator, ®_force_disable_fops); mode = 0; if (ops->get_voltage || ops->get_voltage_sel) mode |= 0444; if (ops->set_voltage || ops->set_voltage_sel) mode |= 0200; if (mode) debugfs_create_file("voltage", mode, rdev->debugfs, regulator, ®_voltage_fops); mode = 0; if (ops->get_mode) mode |= 0444; if (ops->set_mode) mode |= 0200; if (mode) debugfs_create_file("mode", mode, rdev->debugfs, regulator, ®_mode_fops); mode = 0; if (ops->get_mode) mode |= 0444; if (ops->set_load || (ops->get_optimum_mode && ops->set_mode)) mode |= 0200; if (mode) debugfs_create_file("load", mode, rdev->debugfs, regulator, ®_set_load_fops); } #else static inline void rdev_deinit_debugfs(struct regulator_dev *rdev) { } static inline void rdev_init_debugfs(struct regulator_dev *rdev) { } #endif static int regulator_register_resolve_supply(struct device *dev, void *data) { struct regulator_dev *rdev = dev_to_rdev(dev); Loading Loading @@ -4442,8 +4779,8 @@ void regulator_unregister(struct regulator_dev *rdev) regulator_disable(rdev->supply); regulator_put(rdev->supply); } rdev_deinit_debugfs(rdev); mutex_lock(®ulator_list_mutex); debugfs_remove_recursive(rdev->debugfs); flush_work(&rdev->disable_work.work); WARN_ON(rdev->open_count); unset_regulator_supplies(rdev); Loading
drivers/regulator/internal.h +1 −0 Original line number Diff line number Diff line Loading @@ -43,6 +43,7 @@ struct regulator { unsigned int bypass:1; int uA_load; struct regulator_voltage voltage[REGULATOR_STATES_NUM]; int enabled; const char *supply_name; struct device_attribute dev_attr; struct regulator_dev *rdev; Loading
include/linux/regulator/driver.h +2 −0 Original line number Diff line number Diff line Loading @@ -440,6 +440,7 @@ struct regulator_dev { int exclusive; u32 use_count; u32 open_count; u32 open_offset; u32 bypass_count; /* lists we belong to */ Loading Loading @@ -475,6 +476,7 @@ struct regulator_dev { /* time when this regulator was disabled last time */ unsigned long last_off_jiffy; struct regulator *debug_consumer; }; struct regulator_dev * Loading