From: Brandon Leong <bleong@codeaurora.org>
To: lrg@slimlogic.co.uk, broonie@opensource.wolfsonmicro.com
Cc: dwalker@codeaurora.org, davidb@codeaurora.org,
linux-arm-msm@vger.kernel.org,
Brandon Leong <bleong@codeaurora.org>
Subject: [PATCH] regulator: debugfs: Adding debugfs functions into regulator framework
Date: Mon, 6 Dec 2010 12:52:43 -0800 [thread overview]
Message-ID: <1291668763-15734-1-git-send-email-bleong@codeaurora.org> (raw)
Allow the user to read and edit regulator information in user space
through the debugfs file system.
Signed-off-by: Brandon Leong <bleong@codeaurora.org>
---
drivers/regulator/core.c | 335 ++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 335 insertions(+), 0 deletions(-)
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index e63366f..2004e17 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -23,6 +23,8 @@
#include <linux/mutex.h>
#include <linux/suspend.h>
#include <linux/delay.h>
+#include <linux/debugfs.h>
+#include <linux/uaccess.h>
#include <linux/regulator/consumer.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
@@ -2270,6 +2272,336 @@ 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 struct dentry *debugfs_base;
+
+static int reg_debug_init(void)
+{
+ debugfs_base = debugfs_create_dir("regulator", NULL);
+ if (IS_ERR(debugfs_base) || debugfs_base == NULL) {
+ pr_err("debugfs_create_dir returned error"
+ " %ld\n", PTR_ERR(debugfs_base));
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+/**
+ * regulator_debug_create_directory - Creates debugfs directories and files
+ * for each regulator
+ *
+ * @param regulator_dev Voltage/Current regulator class device.
+ *
+ * Description: This function is run everytime "regulator_register" is run.
+ * It is called for every regulator and initilaizes both the
+ * regulator directory and the data files inside (ex. enable,
+ * get/set voltage etc).
+ */
+static int regulator_debug_create_directory(struct regulator_dev *regulator_dev)
+{
+ struct dentry *reg_subdir;
+ struct dentry *err_ptr;
+ struct regulator *reg;
+ struct regulator_ops *reg_ops;
+ mode_t mode;
+ if (IS_ERR(regulator_dev) || regulator_dev == NULL ||
+ IS_ERR(debugfs_base) || debugfs_base == NULL) {
+ pr_err("Error-Bad Input\n");
+ goto error;
+ }
+
+ reg_subdir = debugfs_create_dir(regulator_dev->desc->name,
+ debugfs_base);
+
+ reg = regulator_get(NULL, regulator_dev->desc->name);
+ if (IS_ERR(reg) || reg == NULL) {
+ pr_err("Error-Bad Input\n");
+ goto error;
+ }
+
+ reg_ops = regulator_dev->desc->ops;
+ mode = 0;
+ /* Enabled 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("enable", mode, reg_subdir,
+ reg, ®_enable_fops);
+ if (IS_ERR(err_ptr)) {
+ pr_err("Error-Could not create enable file\n");
+ debugfs_remove_recursive(reg_subdir);
+ 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,
+ reg_subdir, reg, ®_fdisable_fops);
+ if (IS_ERR(err_ptr)) {
+ pr_err("Error-Could not create force_disable file\n");
+ debugfs_remove_recursive(reg_subdir);
+ 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, reg_subdir,
+ reg, ®_volt_fops);
+ if (IS_ERR(err_ptr)) {
+ pr_err("Error-Could not create voltage file\n");
+ debugfs_remove_recursive(reg_subdir);
+ 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, reg_subdir,
+ reg, ®_mode_fops);
+ if (IS_ERR(err_ptr)) {
+ pr_err("Error-Could not create mode file\n");
+ debugfs_remove_recursive(reg_subdir);
+ 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,
+ reg_subdir, reg, ®_optimum_mode_fops);
+ if (IS_ERR(err_ptr)) {
+ pr_err("Error-Could not create optimum_mode file\n");
+ debugfs_remove_recursive(reg_subdir);
+ goto error;
+ }
+
+ return 0;
+
+error:
+ return -ENOMEM;
+}
+#else
+static inline void regulator_debug_create_directory(struct regulator_dev
+ *regulator_dev)
+{
+ return;
+}
+
+static inline void reg_debug_init(void)
+{
+ return;
+}
+#endif
+
/**
* regulator_register - register regulator
* @regulator_desc: regulator to register
@@ -2400,6 +2732,7 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc,
list_add(&rdev->list, ®ulator_list);
out:
mutex_unlock(®ulator_list_mutex);
+ regulator_debug_create_directory(rdev);
return rdev;
unset_supplies:
@@ -2575,6 +2908,8 @@ static int __init regulator_init(void)
regulator_dummy_init();
+ reg_debug_init();
+
return ret;
}
--
1.7.3.1
--
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
next reply other threads:[~2010-12-06 20:52 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2010-12-06 20:52 Brandon Leong [this message]
2010-12-06 22:29 ` [PATCH] regulator: debugfs: Adding debugfs functions into regulator framework Mark Brown
2010-12-07 2:52 ` Daniel Walker
2010-12-07 11:57 ` Mark Brown
2010-12-07 22:04 ` Brandon Leong
2010-12-07 22:37 ` Mark Brown
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1291668763-15734-1-git-send-email-bleong@codeaurora.org \
--to=bleong@codeaurora.org \
--cc=broonie@opensource.wolfsonmicro.com \
--cc=davidb@codeaurora.org \
--cc=dwalker@codeaurora.org \
--cc=linux-arm-msm@vger.kernel.org \
--cc=lrg@slimlogic.co.uk \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).