aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base/regmap/regmap-debugfs.c
diff options
context:
space:
mode:
authorMark Brown <broonie@opensource.wolfsonmicro.com>2011-07-20 17:56:53 -0400
committerMark Brown <broonie@opensource.wolfsonmicro.com>2011-08-08 02:57:00 -0400
commit31244e396fa9e4854cfd6dfe305983e77802c156 (patch)
treed2d9b4403802e8536e83304b3024352ba529f1fe /drivers/base/regmap/regmap-debugfs.c
parent93de91245b66f20dd387c2745744950a11a5c436 (diff)
regmap: Provide register map dump via debugfs
Copy over the read parts of the ASoC debugfs implementation into regmap, allowing users to see what the register values the device has are at runtime. The implementation, especially the support for seeking, is mostly due to Dimitris Papastamos' work in ASoC. Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'drivers/base/regmap/regmap-debugfs.c')
-rw-r--r--drivers/base/regmap/regmap-debugfs.c131
1 files changed, 131 insertions, 0 deletions
diff --git a/drivers/base/regmap/regmap-debugfs.c b/drivers/base/regmap/regmap-debugfs.c
new file mode 100644
index 000000000000..2be8bf86825b
--- /dev/null
+++ b/drivers/base/regmap/regmap-debugfs.c
@@ -0,0 +1,131 @@
1/*
2 * Register map access API - debugfs
3 *
4 * Copyright 2011 Wolfson Microelectronics plc
5 *
6 * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12
13#include <linux/slab.h>
14#include <linux/module.h>
15#include <linux/mutex.h>
16#include <linux/debugfs.h>
17#include <linux/uaccess.h>
18
19#include "internal.h"
20
21static struct dentry *regmap_debugfs_root;
22
23static int regmap_map_open_file(struct inode *inode, struct file *file)
24{
25 file->private_data = inode->i_private;
26 return 0;
27}
28
29static ssize_t regmap_map_read_file(struct file *file, char __user *user_buf,
30 size_t count, loff_t *ppos)
31{
32 size_t reg_len, val_len, tot_len;
33 size_t buf_pos = 0;
34 loff_t p = 0;
35 ssize_t ret;
36 int i;
37 struct regmap *map = file->private_data;
38 char *buf;
39 unsigned int val;
40
41 if (*ppos < 0 || !count)
42 return -EINVAL;
43
44 buf = kmalloc(count, GFP_KERNEL);
45 if (!buf)
46 return -ENOMEM;
47
48 /* Calculate the length of a fixed format */
49 snprintf(buf, count, "%x", map->max_register);
50 reg_len = strlen(buf);
51 val_len = 2 * map->format.val_bytes;
52 tot_len = reg_len + val_len + 3; /* : \n */
53
54 for (i = 0; i < map->max_register; i++) {
55 if (map->readable_reg &&
56 !map->readable_reg(map->dev, i))
57 continue;
58
59 /* If we're in the region the user is trying to read */
60 if (p >= *ppos) {
61 /* ...but not beyond it */
62 if (buf_pos >= count - 1 - tot_len)
63 break;
64
65 /* Format the register */
66 snprintf(buf + buf_pos, count - buf_pos, "%.*x: ",
67 reg_len, i);
68 buf_pos += reg_len + 2;
69
70 /* Format the value, write all X if we can't read */
71 ret = regmap_read(map, i, &val);
72 if (ret == 0)
73 snprintf(buf + buf_pos, count - buf_pos,
74 "%.*x", val_len, val);
75 else
76 memset(buf + buf_pos, 'X', val_len);
77 buf_pos += 2 * map->format.val_bytes;
78
79 buf[buf_pos++] = '\n';
80 }
81 p += tot_len;
82 }
83
84 ret = buf_pos;
85
86 if (copy_to_user(user_buf, buf, buf_pos)) {
87 ret = -EFAULT;
88 goto out;
89 }
90
91 *ppos += buf_pos;
92
93out:
94 kfree(buf);
95 return ret;
96}
97
98static const struct file_operations regmap_map_fops = {
99 .open = regmap_map_open_file,
100 .read = regmap_map_read_file,
101 .llseek = default_llseek,
102};
103
104
105void regmap_debugfs_init(struct regmap *map)
106{
107 map->debugfs = debugfs_create_dir(dev_name(map->dev),
108 regmap_debugfs_root);
109 if (!map->debugfs) {
110 dev_warn(map->dev, "Failed to create debugfs directory\n");
111 return;
112 }
113
114 if (map->max_register)
115 debugfs_create_file("registers", 0400, map->debugfs,
116 map, &regmap_map_fops);
117}
118
119void regmap_debugfs_exit(struct regmap *map)
120{
121 debugfs_remove_recursive(map->debugfs);
122}
123
124void regmap_debugfs_initcall(void)
125{
126 regmap_debugfs_root = debugfs_create_dir("regmap", NULL);
127 if (!regmap_debugfs_root) {
128 pr_warn("regmap: Failed to create debugfs root\n");
129 return;
130 }
131}