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