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/module.h> 15 #include <linux/mutex.h> 16 #include <linux/debugfs.h> 17 #include <linux/uaccess.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_map_read_file(struct file *file, char __user *user_buf, 37 size_t count, loff_t *ppos) 38 { 39 int reg_len, val_len, tot_len; 40 size_t buf_pos = 0; 41 loff_t p = 0; 42 ssize_t ret; 43 int i; 44 struct regmap *map = file->private_data; 45 char *buf; 46 unsigned int val; 47 48 if (*ppos < 0 || !count) 49 return -EINVAL; 50 51 buf = kmalloc(count, GFP_KERNEL); 52 if (!buf) 53 return -ENOMEM; 54 55 /* Calculate the length of a fixed format */ 56 reg_len = regmap_calc_reg_len(map->max_register, buf, count); 57 val_len = 2 * map->format.val_bytes; 58 tot_len = reg_len + val_len + 3; /* : \n */ 59 60 for (i = 0; i < map->max_register + 1; i++) { 61 if (!regmap_readable(map, i)) 62 continue; 63 64 if (regmap_precious(map, i)) 65 continue; 66 67 /* If we're in the region the user is trying to read */ 68 if (p >= *ppos) { 69 /* ...but not beyond it */ 70 if (buf_pos >= count - 1 - tot_len) 71 break; 72 73 /* Format the register */ 74 snprintf(buf + buf_pos, count - buf_pos, "%.*x: ", 75 reg_len, i); 76 buf_pos += reg_len + 2; 77 78 /* Format the value, write all X if we can't read */ 79 ret = regmap_read(map, i, &val); 80 if (ret == 0) 81 snprintf(buf + buf_pos, count - buf_pos, 82 "%.*x", val_len, val); 83 else 84 memset(buf + buf_pos, 'X', val_len); 85 buf_pos += 2 * map->format.val_bytes; 86 87 buf[buf_pos++] = '\n'; 88 } 89 p += tot_len; 90 } 91 92 ret = buf_pos; 93 94 if (copy_to_user(user_buf, buf, buf_pos)) { 95 ret = -EFAULT; 96 goto out; 97 } 98 99 *ppos += buf_pos; 100 101 out: 102 kfree(buf); 103 return ret; 104 } 105 106 static const struct file_operations regmap_map_fops = { 107 .open = regmap_open_file, 108 .read = regmap_map_read_file, 109 .llseek = default_llseek, 110 }; 111 112 static 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 + 1; 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 169 out: 170 kfree(buf); 171 return ret; 172 } 173 174 static const struct file_operations regmap_access_fops = { 175 .open = regmap_open_file, 176 .read = regmap_access_read_file, 177 .llseek = default_llseek, 178 }; 179 180 void regmap_debugfs_init(struct regmap *map) 181 { 182 map->debugfs = debugfs_create_dir(dev_name(map->dev), 183 regmap_debugfs_root); 184 if (!map->debugfs) { 185 dev_warn(map->dev, "Failed to create debugfs directory\n"); 186 return; 187 } 188 189 if (map->max_register) { 190 debugfs_create_file("registers", 0400, map->debugfs, 191 map, ®map_map_fops); 192 debugfs_create_file("access", 0400, map->debugfs, 193 map, ®map_access_fops); 194 } 195 } 196 197 void regmap_debugfs_exit(struct regmap *map) 198 { 199 debugfs_remove_recursive(map->debugfs); 200 } 201 202 void regmap_debugfs_initcall(void) 203 { 204 regmap_debugfs_root = debugfs_create_dir("regmap", NULL); 205 if (!regmap_debugfs_root) { 206 pr_warn("regmap: Failed to create debugfs root\n"); 207 return; 208 } 209 } 210