blob: fff8e832a985ff3963cebdda175c8277ceb759ff [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>
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{
Mark Browncb3c2dc2011-08-09 16:47:42 +090032 int reg_len, val_len, tot_len;
Mark Brown31244e32011-07-20 22:56:53 +010033 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++) {
Mark Brown8de2f082011-08-10 17:14:41 +090055 if (!regmap_readable(map, i))
Mark Brown31244e32011-07-20 22:56:53 +010056 continue;
57
Mark Brown8de2f082011-08-10 17:14:41 +090058 if (regmap_precious(map, i))
Mark Brown2efe1642011-08-08 15:41:46 +090059 continue;
60
Mark Brown31244e32011-07-20 22:56:53 +010061 /* If we're in the region the user is trying to read */
62 if (p >= *ppos) {
63 /* ...but not beyond it */
64 if (buf_pos >= count - 1 - tot_len)
65 break;
66
67 /* Format the register */
68 snprintf(buf + buf_pos, count - buf_pos, "%.*x: ",
69 reg_len, i);
70 buf_pos += reg_len + 2;
71
72 /* Format the value, write all X if we can't read */
73 ret = regmap_read(map, i, &val);
74 if (ret == 0)
75 snprintf(buf + buf_pos, count - buf_pos,
76 "%.*x", val_len, val);
77 else
78 memset(buf + buf_pos, 'X', val_len);
79 buf_pos += 2 * map->format.val_bytes;
80
81 buf[buf_pos++] = '\n';
82 }
83 p += tot_len;
84 }
85
86 ret = buf_pos;
87
88 if (copy_to_user(user_buf, buf, buf_pos)) {
89 ret = -EFAULT;
90 goto out;
91 }
92
93 *ppos += buf_pos;
94
95out:
96 kfree(buf);
97 return ret;
98}
99
100static const struct file_operations regmap_map_fops = {
101 .open = regmap_map_open_file,
102 .read = regmap_map_read_file,
103 .llseek = default_llseek,
104};
105
106
107void regmap_debugfs_init(struct regmap *map)
108{
109 map->debugfs = debugfs_create_dir(dev_name(map->dev),
110 regmap_debugfs_root);
111 if (!map->debugfs) {
112 dev_warn(map->dev, "Failed to create debugfs directory\n");
113 return;
114 }
115
116 if (map->max_register)
117 debugfs_create_file("registers", 0400, map->debugfs,
118 map, &regmap_map_fops);
119}
120
121void regmap_debugfs_exit(struct regmap *map)
122{
123 debugfs_remove_recursive(map->debugfs);
124}
125
126void regmap_debugfs_initcall(void)
127{
128 regmap_debugfs_root = debugfs_create_dir("regmap", NULL);
129 if (!regmap_debugfs_root) {
130 pr_warn("regmap: Failed to create debugfs root\n");
131 return;
132 }
133}