aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base/regmap/regmap-debugfs.c
diff options
context:
space:
mode:
authorMark Brown <broonie@opensource.wolfsonmicro.com>2011-08-10 04:28:04 -0400
committerMark Brown <broonie@opensource.wolfsonmicro.com>2011-08-14 06:51:16 -0400
commit449e38427fe57a6120fecd1051981c89ee862b3d (patch)
treec8c7d4b24b799c6bf5f601776f7e1671b9a419cf /drivers/base/regmap/regmap-debugfs.c
parent21f555445676e5c7d30bb9b3487cb183d02e45e3 (diff)
regmap: Provide access information via debugfs
Let userspace know what the access map for the device is. This is helpful for verifying that the access map is correctly configured and could also be useful for programs that try to work with the data. File format is: register: R W V P where R, W, V and P are 'y' or 'n' showing readable, writable, volatile and precious respectively. 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.c72
1 files changed, 71 insertions, 1 deletions
diff --git a/drivers/base/regmap/regmap-debugfs.c b/drivers/base/regmap/regmap-debugfs.c
index e541d7f4b4e0..7a8d67537d3f 100644
--- a/drivers/base/regmap/regmap-debugfs.c
+++ b/drivers/base/regmap/regmap-debugfs.c
@@ -109,6 +109,73 @@ static const struct file_operations regmap_map_fops = {
109 .llseek = default_llseek, 109 .llseek = default_llseek,
110}; 110};
111 111
112static ssize_t regmap_access_read_file(struct file *file,
113 char __user *user_buf, size_t count,
114 loff_t *ppos)
115{
116 int reg_len, tot_len;
117 size_t buf_pos = 0;
118 loff_t p = 0;
119 ssize_t ret;
120 int i;
121 struct regmap *map = file->private_data;
122 char *buf;
123
124 if (*ppos < 0 || !count)
125 return -EINVAL;
126
127 buf = kmalloc(count, GFP_KERNEL);
128 if (!buf)
129 return -ENOMEM;
130
131 /* Calculate the length of a fixed format */
132 reg_len = regmap_calc_reg_len(map->max_register, buf, count);
133 tot_len = reg_len + 10; /* ': R W V P\n' */
134
135 for (i = 0; i < map->max_register; i++) {
136 /* Ignore registers which are neither readable nor writable */
137 if (!regmap_readable(map, i) && !regmap_writeable(map, i))
138 continue;
139
140 /* If we're in the region the user is trying to read */
141 if (p >= *ppos) {
142 /* ...but not beyond it */
143 if (buf_pos >= count - 1 - tot_len)
144 break;
145
146 /* Format the register */
147 snprintf(buf + buf_pos, count - buf_pos,
148 "%.*x: %c %c %c %c\n",
149 reg_len, i,
150 regmap_readable(map, i) ? 'y' : 'n',
151 regmap_writeable(map, i) ? 'y' : 'n',
152 regmap_volatile(map, i) ? 'y' : 'n',
153 regmap_precious(map, i) ? 'y' : 'n');
154
155 buf_pos += tot_len;
156 }
157 p += tot_len;
158 }
159
160 ret = buf_pos;
161
162 if (copy_to_user(user_buf, buf, buf_pos)) {
163 ret = -EFAULT;
164 goto out;
165 }
166
167 *ppos += buf_pos;
168
169out:
170 kfree(buf);
171 return ret;
172}
173
174static const struct file_operations regmap_access_fops = {
175 .open = regmap_open_file,
176 .read = regmap_access_read_file,
177 .llseek = default_llseek,
178};
112 179
113void regmap_debugfs_init(struct regmap *map) 180void regmap_debugfs_init(struct regmap *map)
114{ 181{
@@ -119,9 +186,12 @@ void regmap_debugfs_init(struct regmap *map)
119 return; 186 return;
120 } 187 }
121 188
122 if (map->max_register) 189 if (map->max_register) {
123 debugfs_create_file("registers", 0400, map->debugfs, 190 debugfs_create_file("registers", 0400, map->debugfs,
124 map, &regmap_map_fops); 191 map, &regmap_map_fops);
192 debugfs_create_file("access", 0400, map->debugfs,
193 map, &regmap_access_fops);
194 }
125} 195}
126 196
127void regmap_debugfs_exit(struct regmap *map) 197void regmap_debugfs_exit(struct regmap *map)