summaryrefslogtreecommitdiff
path: root/drivers/base/regmap/regmap-debugfs.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/base/regmap/regmap-debugfs.c')
-rw-r--r--drivers/base/regmap/regmap-debugfs.c75
1 files changed, 72 insertions, 3 deletions
diff --git a/drivers/base/regmap/regmap-debugfs.c b/drivers/base/regmap/regmap-debugfs.c
index 3f0a7e262d69..3120bdc84fce 100644
--- a/drivers/base/regmap/regmap-debugfs.c
+++ b/drivers/base/regmap/regmap-debugfs.c
@@ -259,8 +259,7 @@ static ssize_t regmap_map_read_file(struct file *file, char __user *user_buf,
count, ppos);
}
-#undef REGMAP_ALLOW_WRITE_DEBUGFS
-#ifdef REGMAP_ALLOW_WRITE_DEBUGFS
+#ifdef CONFIG_REGMAP_ALLOW_WRITE_DEBUGFS
/*
* This can be dangerous especially when we have clients such as
* PMICs, therefore don't provide any real compile time configuration option
@@ -310,6 +309,67 @@ static const struct file_operations regmap_map_fops = {
.llseek = default_llseek,
};
+static ssize_t regmap_data_read_file(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct regmap *map = file->private_data;
+ int new_count;
+
+ regmap_calc_tot_len(map, NULL, 0);
+ new_count = map->dump_count * map->debugfs_tot_len;
+ if (new_count > count)
+ new_count = count;
+
+ if (*ppos == 0)
+ *ppos = map->dump_address * map->debugfs_tot_len;
+ else if (*ppos >= map->dump_address * map->debugfs_tot_len
+ + map->dump_count * map->debugfs_tot_len)
+ return 0;
+ return regmap_read_debugfs(map, 0, map->max_register, user_buf,
+ new_count, ppos);
+}
+
+#ifdef CONFIG_REGMAP_ALLOW_WRITE_DEBUGFS
+static ssize_t regmap_data_write_file(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ char buf[32];
+ size_t buf_size;
+ char *start = buf;
+ unsigned long value;
+ struct regmap *map = file->private_data;
+ int ret;
+
+ buf_size = min(count, (sizeof(buf)-1));
+ if (copy_from_user(buf, user_buf, buf_size))
+ return -EFAULT;
+ buf[buf_size] = 0;
+
+ while (*start == ' ')
+ start++;
+ if (kstrtoul(start, 16, &value))
+ return -EINVAL;
+
+ /* Userspace has been fiddling around behind the kernel's back */
+ add_taint(TAINT_USER, LOCKDEP_STILL_OK);
+
+ ret = regmap_write(map, map->dump_address, value);
+ if (ret < 0)
+ return ret;
+ return buf_size;
+}
+#else
+#define regmap_data_write_file NULL
+#endif
+
+static const struct file_operations regmap_data_fops = {
+ .open = simple_open,
+ .read = regmap_data_read_file,
+ .write = regmap_data_write_file,
+ .llseek = default_llseek,
+};
+
static ssize_t regmap_range_read_file(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
@@ -595,7 +655,7 @@ void regmap_debugfs_init(struct regmap *map, const char *name)
if (map->max_register || regmap_readable(map, 0)) {
umode_t registers_mode;
-#if defined(REGMAP_ALLOW_WRITE_DEBUGFS)
+#ifdef CONFIG_REGMAP_ALLOW_WRITE_DEBUGFS
registers_mode = 0600;
#else
registers_mode = 0400;
@@ -603,6 +663,15 @@ void regmap_debugfs_init(struct regmap *map, const char *name)
debugfs_create_file("registers", registers_mode, map->debugfs,
map, &regmap_map_fops);
+
+ debugfs_create_x32("address", 0600, map->debugfs,
+ &map->dump_address);
+ map->dump_count = 1;
+ debugfs_create_u32("count", 0600, map->debugfs,
+ &map->dump_count);
+ debugfs_create_file("data", registers_mode, map->debugfs,
+ map, &regmap_data_fops);
+
debugfs_create_file("access", 0400, map->debugfs,
map, &regmap_access_fops);
}