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/mutex.h> 15 #include <linux/debugfs.h> 16 #include <linux/uaccess.h> 17 #include <linux/device.h> 18 19 #include "internal.h" 20 21 static struct dentry *regmap_debugfs_root; 22 23 /* Calculate the length of a fixed format */ 24 static 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 30 static int regmap_open_file(struct inode *inode, struct file *file) 31 { 32 file->private_data = inode->i_private; 33 return 0; 34 } 35 36 static ssize_t regmap_name_read_file(struct file *file, 37 char __user *user_buf, size_t count, 38 loff_t *ppos) 39 { 40 struct regmap *map = file->private_data; 41 int ret; 42 char *buf; 43 44 buf = kmalloc(PAGE_SIZE, GFP_KERNEL); 45 if (!buf) 46 return -ENOMEM; 47 48 ret = snprintf(buf, PAGE_SIZE, "%s\n", map->dev->driver->name); 49 if (ret < 0) { 50 kfree(buf); 51 return ret; 52 } 53 54 ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret); 55 kfree(buf); 56 return ret; 57 } 58 59 static const struct file_operations regmap_name_fops = { 60 .open = regmap_open_file, 61 .read = regmap_name_read_file, 62 .llseek = default_llseek, 63 }; 64 65 static ssize_t regmap_map_read_file(struct file *file, char __user *user_buf, 66 size_t count, loff_t *ppos) 67 { 68 int reg_len, val_len, tot_len; 69 size_t buf_pos = 0; 70 loff_t p = 0; 71 ssize_t ret; 72 int i; 73 struct regmap *map = file->private_data; 74 char *buf; 75 unsigned int val; 76 77 if (*ppos < 0 || !count) 78 return -EINVAL; 79 80 buf = kmalloc(count, GFP_KERNEL); 81 if (!buf) 82 return -ENOMEM; 83 84 /* Calculate the length of a fixed format */ 85 reg_len = regmap_calc_reg_len(map->max_register, buf, count); 86 val_len = 2 * map->format.val_bytes; 87 tot_len = reg_len + val_len + 3; /* : \n */ 88 89 for (i = 0; i < map->max_register + 1; i++) { 90 if (!regmap_readable(map, i)) 91 continue; 92 93 if (regmap_precious(map, i)) 94 continue; 95 96 /* If we're in the region the user is trying to read */ 97 if (p >= *ppos) { 98 /* ...but not beyond it */ 99 if (buf_pos >= count - 1 - tot_len) 100 break; 101 102 /* Format the register */ 103 snprintf(buf + buf_pos, count - buf_pos, "%.*x: ", 104 reg_len, i); 105 buf_pos += reg_len + 2; 106 107 /* Format the value, write all X if we can't read */ 108 ret = regmap_read(map, i, &val); 109 if (ret == 0) 110 snprintf(buf + buf_pos, count - buf_pos, 111 "%.*x", val_len, val); 112 else 113 memset(buf + buf_pos, 'X', val_len); 114 buf_pos += 2 * map->format.val_bytes; 115 116 buf[buf_pos++] = '\n'; 117 } 118 p += tot_len; 119 } 120 121 ret = buf_pos; 122 123 if (copy_to_user(user_buf, buf, buf_pos)) { 124 ret = -EFAULT; 125 goto out; 126 } 127 128 *ppos += buf_pos; 129 130 out: 131 kfree(buf); 132 return ret; 133 } 134 135 #undef REGMAP_ALLOW_WRITE_DEBUGFS 136 #ifdef REGMAP_ALLOW_WRITE_DEBUGFS 137 /* 138 * This can be dangerous especially when we have clients such as 139 * PMICs, therefore don't provide any real compile time configuration option 140 * for this feature, people who want to use this will need to modify 141 * the source code directly. 142 */ 143 static ssize_t regmap_map_write_file(struct file *file, 144 const char __user *user_buf, 145 size_t count, loff_t *ppos) 146 { 147 char buf[32]; 148 size_t buf_size; 149 char *start = buf; 150 unsigned long reg, value; 151 struct regmap *map = file->private_data; 152 153 buf_size = min(count, (sizeof(buf)-1)); 154 if (copy_from_user(buf, user_buf, buf_size)) 155 return -EFAULT; 156 buf[buf_size] = 0; 157 158 while (*start == ' ') 159 start++; 160 reg = simple_strtoul(start, &start, 16); 161 while (*start == ' ') 162 start++; 163 if (strict_strtoul(start, 16, &value)) 164 return -EINVAL; 165 166 /* Userspace has been fiddling around behind the kernel's back */ 167 add_taint(TAINT_USER); 168 169 regmap_write(map, reg, value); 170 return buf_size; 171 } 172 #else 173 #define regmap_map_write_file NULL 174 #endif 175 176 static const struct file_operations regmap_map_fops = { 177 .open = regmap_open_file, 178 .read = regmap_map_read_file, 179 .write = regmap_map_write_file, 180 .llseek = default_llseek, 181 }; 182 183 static ssize_t regmap_access_read_file(struct file *file, 184 char __user *user_buf, size_t count, 185 loff_t *ppos) 186 { 187 int reg_len, tot_len; 188 size_t buf_pos = 0; 189 loff_t p = 0; 190 ssize_t ret; 191 int i; 192 struct regmap *map = file->private_data; 193 char *buf; 194 195 if (*ppos < 0 || !count) 196 return -EINVAL; 197 198 buf = kmalloc(count, GFP_KERNEL); 199 if (!buf) 200 return -ENOMEM; 201 202 /* Calculate the length of a fixed format */ 203 reg_len = regmap_calc_reg_len(map->max_register, buf, count); 204 tot_len = reg_len + 10; /* ': R W V P\n' */ 205 206 for (i = 0; i < map->max_register + 1; i++) { 207 /* Ignore registers which are neither readable nor writable */ 208 if (!regmap_readable(map, i) && !regmap_writeable(map, i)) 209 continue; 210 211 /* If we're in the region the user is trying to read */ 212 if (p >= *ppos) { 213 /* ...but not beyond it */ 214 if (buf_pos >= count - 1 - tot_len) 215 break; 216 217 /* Format the register */ 218 snprintf(buf + buf_pos, count - buf_pos, 219 "%.*x: %c %c %c %c\n", 220 reg_len, i, 221 regmap_readable(map, i) ? 'y' : 'n', 222 regmap_writeable(map, i) ? 'y' : 'n', 223 regmap_volatile(map, i) ? 'y' : 'n', 224 regmap_precious(map, i) ? 'y' : 'n'); 225 226 buf_pos += tot_len; 227 } 228 p += tot_len; 229 } 230 231 ret = buf_pos; 232 233 if (copy_to_user(user_buf, buf, buf_pos)) { 234 ret = -EFAULT; 235 goto out; 236 } 237 238 *ppos += buf_pos; 239 240 out: 241 kfree(buf); 242 return ret; 243 } 244 245 static const struct file_operations regmap_access_fops = { 246 .open = regmap_open_file, 247 .read = regmap_access_read_file, 248 .llseek = default_llseek, 249 }; 250 251 void regmap_debugfs_init(struct regmap *map) 252 { 253 map->debugfs = debugfs_create_dir(dev_name(map->dev), 254 regmap_debugfs_root); 255 if (!map->debugfs) { 256 dev_warn(map->dev, "Failed to create debugfs directory\n"); 257 return; 258 } 259 260 debugfs_create_file("name", 0400, map->debugfs, 261 map, ®map_name_fops); 262 263 if (map->max_register) { 264 debugfs_create_file("registers", 0400, map->debugfs, 265 map, ®map_map_fops); 266 debugfs_create_file("access", 0400, map->debugfs, 267 map, ®map_access_fops); 268 } 269 270 if (map->cache_type) { 271 debugfs_create_bool("cache_only", 0400, map->debugfs, 272 &map->cache_only); 273 debugfs_create_bool("cache_dirty", 0400, map->debugfs, 274 &map->cache_dirty); 275 debugfs_create_bool("cache_bypass", 0400, map->debugfs, 276 &map->cache_bypass); 277 } 278 } 279 280 void regmap_debugfs_exit(struct regmap *map) 281 { 282 debugfs_remove_recursive(map->debugfs); 283 } 284 285 void regmap_debugfs_initcall(void) 286 { 287 regmap_debugfs_root = debugfs_create_dir("regmap", NULL); 288 if (!regmap_debugfs_root) { 289 pr_warn("regmap: Failed to create debugfs root\n"); 290 return; 291 } 292 } 293