blob: 749a1dc5bbfbbbf5e371ac712979b6c8e422a500 [file] [log] [blame]
Mark Brown31244e32011-07-20 22:56:53 +01001/*
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>
Mark Brown31244e32011-07-20 22:56:53 +010014#include <linux/mutex.h>
15#include <linux/debugfs.h>
16#include <linux/uaccess.h>
Paul Gortmaker51990e82012-01-22 11:23:42 -050017#include <linux/device.h>
Mark Brown31244e32011-07-20 22:56:53 +010018
19#include "internal.h"
20
21static struct dentry *regmap_debugfs_root;
22
Mark Brown21f55542011-08-10 17:15:31 +090023/* Calculate the length of a fixed format */
24static size_t regmap_calc_reg_len(int max_val, char *buf, size_t buf_size)
25{
26 snprintf(buf, buf_size, "%x", max_val);
27 return strlen(buf);
28}
29
Dimitris Papastamosf0c23192012-02-22 14:20:09 +000030static ssize_t regmap_name_read_file(struct file *file,
31 char __user *user_buf, size_t count,
32 loff_t *ppos)
33{
34 struct regmap *map = file->private_data;
35 int ret;
36 char *buf;
37
38 buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
39 if (!buf)
40 return -ENOMEM;
41
42 ret = snprintf(buf, PAGE_SIZE, "%s\n", map->dev->driver->name);
43 if (ret < 0) {
44 kfree(buf);
45 return ret;
46 }
47
48 ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
49 kfree(buf);
50 return ret;
51}
52
53static const struct file_operations regmap_name_fops = {
Stephen Boyd234e3402012-04-05 14:25:11 -070054 .open = simple_open,
Dimitris Papastamosf0c23192012-02-22 14:20:09 +000055 .read = regmap_name_read_file,
56 .llseek = default_llseek,
57};
58
Mark Brownafab2f72012-12-09 17:20:10 +090059/*
60 * Work out where the start offset maps into register numbers, bearing
61 * in mind that we suppress hidden registers.
62 */
63static unsigned int regmap_debugfs_get_dump_start(struct regmap *map,
64 unsigned int base,
65 loff_t from,
66 loff_t *pos)
67{
68 loff_t p = *pos;
69 unsigned int i;
70
71 for (i = base; i <= map->max_register; i += map->reg_stride) {
72 if (!regmap_readable(map, i))
73 continue;
74
75 if (regmap_precious(map, i))
76 continue;
77
78 if (i >= from) {
79 *pos = p;
80 return i;
81 }
82
83 p += map->debugfs_tot_len;
84 }
85
86 return base;
87}
88
Mark Brownbd9cc122012-10-03 12:45:37 +010089static ssize_t regmap_read_debugfs(struct regmap *map, unsigned int from,
90 unsigned int to, char __user *user_buf,
91 size_t count, loff_t *ppos)
Mark Brown31244e32011-07-20 22:56:53 +010092{
Mark Brown31244e32011-07-20 22:56:53 +010093 size_t buf_pos = 0;
Mark Brownafab2f72012-12-09 17:20:10 +090094 loff_t p = *ppos;
Mark Brown31244e32011-07-20 22:56:53 +010095 ssize_t ret;
96 int i;
Mark Brown31244e32011-07-20 22:56:53 +010097 char *buf;
Mark Brownafab2f72012-12-09 17:20:10 +090098 unsigned int val, start_reg;
Mark Brown31244e32011-07-20 22:56:53 +010099
100 if (*ppos < 0 || !count)
101 return -EINVAL;
102
103 buf = kmalloc(count, GFP_KERNEL);
104 if (!buf)
105 return -ENOMEM;
106
107 /* Calculate the length of a fixed format */
Mark Browncbc19382012-12-06 13:29:05 +0900108 if (!map->debugfs_tot_len) {
109 map->debugfs_reg_len = regmap_calc_reg_len(map->max_register,
110 buf, count);
111 map->debugfs_val_len = 2 * map->format.val_bytes;
112 map->debugfs_tot_len = map->debugfs_reg_len +
113 map->debugfs_val_len + 3; /* : \n */
114 }
Mark Brown31244e32011-07-20 22:56:53 +0100115
Mark Brownafab2f72012-12-09 17:20:10 +0900116 /* Work out which register we're starting at */
117 start_reg = regmap_debugfs_get_dump_start(map, from, *ppos, &p);
118
119 for (i = start_reg; i <= to; i += map->reg_stride) {
Mark Brown8de2f082011-08-10 17:14:41 +0900120 if (!regmap_readable(map, i))
Mark Brown31244e32011-07-20 22:56:53 +0100121 continue;
122
Mark Brown8de2f082011-08-10 17:14:41 +0900123 if (regmap_precious(map, i))
Mark Brown2efe1642011-08-08 15:41:46 +0900124 continue;
125
Mark Brown31244e32011-07-20 22:56:53 +0100126 /* If we're in the region the user is trying to read */
127 if (p >= *ppos) {
128 /* ...but not beyond it */
Mark Browndb043282012-12-11 01:14:11 +0900129 if (buf_pos + 1 + map->debugfs_tot_len >= count)
Mark Brown31244e32011-07-20 22:56:53 +0100130 break;
131
132 /* Format the register */
133 snprintf(buf + buf_pos, count - buf_pos, "%.*x: ",
Mark Browncbc19382012-12-06 13:29:05 +0900134 map->debugfs_reg_len, i - from);
135 buf_pos += map->debugfs_reg_len + 2;
Mark Brown31244e32011-07-20 22:56:53 +0100136
137 /* Format the value, write all X if we can't read */
138 ret = regmap_read(map, i, &val);
139 if (ret == 0)
140 snprintf(buf + buf_pos, count - buf_pos,
Mark Browncbc19382012-12-06 13:29:05 +0900141 "%.*x", map->debugfs_val_len, val);
Mark Brown31244e32011-07-20 22:56:53 +0100142 else
Mark Browncbc19382012-12-06 13:29:05 +0900143 memset(buf + buf_pos, 'X',
144 map->debugfs_val_len);
Mark Brown31244e32011-07-20 22:56:53 +0100145 buf_pos += 2 * map->format.val_bytes;
146
147 buf[buf_pos++] = '\n';
148 }
Mark Browncbc19382012-12-06 13:29:05 +0900149 p += map->debugfs_tot_len;
Mark Brown31244e32011-07-20 22:56:53 +0100150 }
151
152 ret = buf_pos;
153
154 if (copy_to_user(user_buf, buf, buf_pos)) {
155 ret = -EFAULT;
156 goto out;
157 }
158
159 *ppos += buf_pos;
160
161out:
162 kfree(buf);
163 return ret;
164}
165
Mark Brownbd9cc122012-10-03 12:45:37 +0100166static ssize_t regmap_map_read_file(struct file *file, char __user *user_buf,
167 size_t count, loff_t *ppos)
168{
169 struct regmap *map = file->private_data;
170
171 return regmap_read_debugfs(map, 0, map->max_register, user_buf,
172 count, ppos);
173}
174
Dimitris Papastamos09c6ecd2012-02-22 12:43:50 +0000175#undef REGMAP_ALLOW_WRITE_DEBUGFS
176#ifdef REGMAP_ALLOW_WRITE_DEBUGFS
177/*
178 * This can be dangerous especially when we have clients such as
179 * PMICs, therefore don't provide any real compile time configuration option
180 * for this feature, people who want to use this will need to modify
181 * the source code directly.
182 */
183static ssize_t regmap_map_write_file(struct file *file,
184 const char __user *user_buf,
185 size_t count, loff_t *ppos)
186{
187 char buf[32];
188 size_t buf_size;
189 char *start = buf;
190 unsigned long reg, value;
191 struct regmap *map = file->private_data;
192
193 buf_size = min(count, (sizeof(buf)-1));
194 if (copy_from_user(buf, user_buf, buf_size))
195 return -EFAULT;
196 buf[buf_size] = 0;
197
198 while (*start == ' ')
199 start++;
200 reg = simple_strtoul(start, &start, 16);
201 while (*start == ' ')
202 start++;
203 if (strict_strtoul(start, 16, &value))
204 return -EINVAL;
205
206 /* Userspace has been fiddling around behind the kernel's back */
207 add_taint(TAINT_USER);
208
209 regmap_write(map, reg, value);
210 return buf_size;
211}
212#else
213#define regmap_map_write_file NULL
214#endif
215
Mark Brown31244e32011-07-20 22:56:53 +0100216static const struct file_operations regmap_map_fops = {
Stephen Boyd234e3402012-04-05 14:25:11 -0700217 .open = simple_open,
Mark Brown31244e32011-07-20 22:56:53 +0100218 .read = regmap_map_read_file,
Dimitris Papastamos09c6ecd2012-02-22 12:43:50 +0000219 .write = regmap_map_write_file,
Mark Brown31244e32011-07-20 22:56:53 +0100220 .llseek = default_llseek,
221};
222
Mark Brown4b020b32012-10-03 13:13:16 +0100223static ssize_t regmap_range_read_file(struct file *file, char __user *user_buf,
224 size_t count, loff_t *ppos)
225{
226 struct regmap_range_node *range = file->private_data;
227 struct regmap *map = range->map;
228
229 return regmap_read_debugfs(map, range->range_min, range->range_max,
230 user_buf, count, ppos);
231}
232
233static const struct file_operations regmap_range_fops = {
234 .open = simple_open,
235 .read = regmap_range_read_file,
236 .llseek = default_llseek,
237};
238
Mark Brown449e3842011-08-10 17:28:04 +0900239static ssize_t regmap_access_read_file(struct file *file,
240 char __user *user_buf, size_t count,
241 loff_t *ppos)
242{
243 int reg_len, tot_len;
244 size_t buf_pos = 0;
245 loff_t p = 0;
246 ssize_t ret;
247 int i;
248 struct regmap *map = file->private_data;
249 char *buf;
250
251 if (*ppos < 0 || !count)
252 return -EINVAL;
253
254 buf = kmalloc(count, GFP_KERNEL);
255 if (!buf)
256 return -ENOMEM;
257
258 /* Calculate the length of a fixed format */
259 reg_len = regmap_calc_reg_len(map->max_register, buf, count);
260 tot_len = reg_len + 10; /* ': R W V P\n' */
261
Stephen Warrenf01ee602012-04-09 13:40:24 -0600262 for (i = 0; i <= map->max_register; i += map->reg_stride) {
Mark Brown449e3842011-08-10 17:28:04 +0900263 /* Ignore registers which are neither readable nor writable */
264 if (!regmap_readable(map, i) && !regmap_writeable(map, i))
265 continue;
266
267 /* If we're in the region the user is trying to read */
268 if (p >= *ppos) {
269 /* ...but not beyond it */
270 if (buf_pos >= count - 1 - tot_len)
271 break;
272
273 /* Format the register */
274 snprintf(buf + buf_pos, count - buf_pos,
275 "%.*x: %c %c %c %c\n",
276 reg_len, i,
277 regmap_readable(map, i) ? 'y' : 'n',
278 regmap_writeable(map, i) ? 'y' : 'n',
279 regmap_volatile(map, i) ? 'y' : 'n',
280 regmap_precious(map, i) ? 'y' : 'n');
281
282 buf_pos += tot_len;
283 }
284 p += tot_len;
285 }
286
287 ret = buf_pos;
288
289 if (copy_to_user(user_buf, buf, buf_pos)) {
290 ret = -EFAULT;
291 goto out;
292 }
293
294 *ppos += buf_pos;
295
296out:
297 kfree(buf);
298 return ret;
299}
300
301static const struct file_operations regmap_access_fops = {
Stephen Boyd234e3402012-04-05 14:25:11 -0700302 .open = simple_open,
Mark Brown449e3842011-08-10 17:28:04 +0900303 .read = regmap_access_read_file,
304 .llseek = default_llseek,
305};
Mark Brown31244e32011-07-20 22:56:53 +0100306
Stephen Warrend3c242e2012-04-04 15:48:29 -0600307void regmap_debugfs_init(struct regmap *map, const char *name)
Mark Brown31244e32011-07-20 22:56:53 +0100308{
Mark Brown4b020b32012-10-03 13:13:16 +0100309 struct rb_node *next;
310 struct regmap_range_node *range_node;
311
Stephen Warrend3c242e2012-04-04 15:48:29 -0600312 if (name) {
313 map->debugfs_name = kasprintf(GFP_KERNEL, "%s-%s",
314 dev_name(map->dev), name);
315 name = map->debugfs_name;
316 } else {
317 name = dev_name(map->dev);
318 }
319
320 map->debugfs = debugfs_create_dir(name, regmap_debugfs_root);
Mark Brown31244e32011-07-20 22:56:53 +0100321 if (!map->debugfs) {
322 dev_warn(map->dev, "Failed to create debugfs directory\n");
323 return;
324 }
325
Dimitris Papastamosf0c23192012-02-22 14:20:09 +0000326 debugfs_create_file("name", 0400, map->debugfs,
327 map, &regmap_name_fops);
328
Mark Brown449e3842011-08-10 17:28:04 +0900329 if (map->max_register) {
Mark Brown31244e32011-07-20 22:56:53 +0100330 debugfs_create_file("registers", 0400, map->debugfs,
331 map, &regmap_map_fops);
Mark Brown449e3842011-08-10 17:28:04 +0900332 debugfs_create_file("access", 0400, map->debugfs,
333 map, &regmap_access_fops);
334 }
Mark Brown028a01e2012-02-06 18:02:06 +0000335
336 if (map->cache_type) {
337 debugfs_create_bool("cache_only", 0400, map->debugfs,
338 &map->cache_only);
339 debugfs_create_bool("cache_dirty", 0400, map->debugfs,
340 &map->cache_dirty);
341 debugfs_create_bool("cache_bypass", 0400, map->debugfs,
342 &map->cache_bypass);
343 }
Mark Brown4b020b32012-10-03 13:13:16 +0100344
345 next = rb_first(&map->range_tree);
346 while (next) {
347 range_node = rb_entry(next, struct regmap_range_node, node);
348
349 if (range_node->name)
350 debugfs_create_file(range_node->name, 0400,
351 map->debugfs, range_node,
352 &regmap_range_fops);
353
354 next = rb_next(&range_node->node);
355 }
Mark Brown31244e32011-07-20 22:56:53 +0100356}
357
358void regmap_debugfs_exit(struct regmap *map)
359{
360 debugfs_remove_recursive(map->debugfs);
Stephen Warrend3c242e2012-04-04 15:48:29 -0600361 kfree(map->debugfs_name);
Mark Brown31244e32011-07-20 22:56:53 +0100362}
363
364void regmap_debugfs_initcall(void)
365{
366 regmap_debugfs_root = debugfs_create_dir("regmap", NULL);
367 if (!regmap_debugfs_root) {
368 pr_warn("regmap: Failed to create debugfs root\n");
369 return;
370 }
371}