1*31244e39SMark Brown /* 2*31244e39SMark Brown * Register map access API - debugfs 3*31244e39SMark Brown * 4*31244e39SMark Brown * Copyright 2011 Wolfson Microelectronics plc 5*31244e39SMark Brown * 6*31244e39SMark Brown * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> 7*31244e39SMark Brown * 8*31244e39SMark Brown * This program is free software; you can redistribute it and/or modify 9*31244e39SMark Brown * it under the terms of the GNU General Public License version 2 as 10*31244e39SMark Brown * published by the Free Software Foundation. 11*31244e39SMark Brown */ 12*31244e39SMark Brown 13*31244e39SMark Brown #include <linux/slab.h> 14*31244e39SMark Brown #include <linux/module.h> 15*31244e39SMark Brown #include <linux/mutex.h> 16*31244e39SMark Brown #include <linux/debugfs.h> 17*31244e39SMark Brown #include <linux/uaccess.h> 18*31244e39SMark Brown 19*31244e39SMark Brown #include "internal.h" 20*31244e39SMark Brown 21*31244e39SMark Brown static struct dentry *regmap_debugfs_root; 22*31244e39SMark Brown 23*31244e39SMark Brown static int regmap_map_open_file(struct inode *inode, struct file *file) 24*31244e39SMark Brown { 25*31244e39SMark Brown file->private_data = inode->i_private; 26*31244e39SMark Brown return 0; 27*31244e39SMark Brown } 28*31244e39SMark Brown 29*31244e39SMark Brown static ssize_t regmap_map_read_file(struct file *file, char __user *user_buf, 30*31244e39SMark Brown size_t count, loff_t *ppos) 31*31244e39SMark Brown { 32*31244e39SMark Brown size_t reg_len, val_len, tot_len; 33*31244e39SMark Brown size_t buf_pos = 0; 34*31244e39SMark Brown loff_t p = 0; 35*31244e39SMark Brown ssize_t ret; 36*31244e39SMark Brown int i; 37*31244e39SMark Brown struct regmap *map = file->private_data; 38*31244e39SMark Brown char *buf; 39*31244e39SMark Brown unsigned int val; 40*31244e39SMark Brown 41*31244e39SMark Brown if (*ppos < 0 || !count) 42*31244e39SMark Brown return -EINVAL; 43*31244e39SMark Brown 44*31244e39SMark Brown buf = kmalloc(count, GFP_KERNEL); 45*31244e39SMark Brown if (!buf) 46*31244e39SMark Brown return -ENOMEM; 47*31244e39SMark Brown 48*31244e39SMark Brown /* Calculate the length of a fixed format */ 49*31244e39SMark Brown snprintf(buf, count, "%x", map->max_register); 50*31244e39SMark Brown reg_len = strlen(buf); 51*31244e39SMark Brown val_len = 2 * map->format.val_bytes; 52*31244e39SMark Brown tot_len = reg_len + val_len + 3; /* : \n */ 53*31244e39SMark Brown 54*31244e39SMark Brown for (i = 0; i < map->max_register; i++) { 55*31244e39SMark Brown if (map->readable_reg && 56*31244e39SMark Brown !map->readable_reg(map->dev, i)) 57*31244e39SMark Brown continue; 58*31244e39SMark Brown 59*31244e39SMark Brown /* If we're in the region the user is trying to read */ 60*31244e39SMark Brown if (p >= *ppos) { 61*31244e39SMark Brown /* ...but not beyond it */ 62*31244e39SMark Brown if (buf_pos >= count - 1 - tot_len) 63*31244e39SMark Brown break; 64*31244e39SMark Brown 65*31244e39SMark Brown /* Format the register */ 66*31244e39SMark Brown snprintf(buf + buf_pos, count - buf_pos, "%.*x: ", 67*31244e39SMark Brown reg_len, i); 68*31244e39SMark Brown buf_pos += reg_len + 2; 69*31244e39SMark Brown 70*31244e39SMark Brown /* Format the value, write all X if we can't read */ 71*31244e39SMark Brown ret = regmap_read(map, i, &val); 72*31244e39SMark Brown if (ret == 0) 73*31244e39SMark Brown snprintf(buf + buf_pos, count - buf_pos, 74*31244e39SMark Brown "%.*x", val_len, val); 75*31244e39SMark Brown else 76*31244e39SMark Brown memset(buf + buf_pos, 'X', val_len); 77*31244e39SMark Brown buf_pos += 2 * map->format.val_bytes; 78*31244e39SMark Brown 79*31244e39SMark Brown buf[buf_pos++] = '\n'; 80*31244e39SMark Brown } 81*31244e39SMark Brown p += tot_len; 82*31244e39SMark Brown } 83*31244e39SMark Brown 84*31244e39SMark Brown ret = buf_pos; 85*31244e39SMark Brown 86*31244e39SMark Brown if (copy_to_user(user_buf, buf, buf_pos)) { 87*31244e39SMark Brown ret = -EFAULT; 88*31244e39SMark Brown goto out; 89*31244e39SMark Brown } 90*31244e39SMark Brown 91*31244e39SMark Brown *ppos += buf_pos; 92*31244e39SMark Brown 93*31244e39SMark Brown out: 94*31244e39SMark Brown kfree(buf); 95*31244e39SMark Brown return ret; 96*31244e39SMark Brown } 97*31244e39SMark Brown 98*31244e39SMark Brown static const struct file_operations regmap_map_fops = { 99*31244e39SMark Brown .open = regmap_map_open_file, 100*31244e39SMark Brown .read = regmap_map_read_file, 101*31244e39SMark Brown .llseek = default_llseek, 102*31244e39SMark Brown }; 103*31244e39SMark Brown 104*31244e39SMark Brown 105*31244e39SMark Brown void regmap_debugfs_init(struct regmap *map) 106*31244e39SMark Brown { 107*31244e39SMark Brown map->debugfs = debugfs_create_dir(dev_name(map->dev), 108*31244e39SMark Brown regmap_debugfs_root); 109*31244e39SMark Brown if (!map->debugfs) { 110*31244e39SMark Brown dev_warn(map->dev, "Failed to create debugfs directory\n"); 111*31244e39SMark Brown return; 112*31244e39SMark Brown } 113*31244e39SMark Brown 114*31244e39SMark Brown if (map->max_register) 115*31244e39SMark Brown debugfs_create_file("registers", 0400, map->debugfs, 116*31244e39SMark Brown map, ®map_map_fops); 117*31244e39SMark Brown } 118*31244e39SMark Brown 119*31244e39SMark Brown void regmap_debugfs_exit(struct regmap *map) 120*31244e39SMark Brown { 121*31244e39SMark Brown debugfs_remove_recursive(map->debugfs); 122*31244e39SMark Brown } 123*31244e39SMark Brown 124*31244e39SMark Brown void regmap_debugfs_initcall(void) 125*31244e39SMark Brown { 126*31244e39SMark Brown regmap_debugfs_root = debugfs_create_dir("regmap", NULL); 127*31244e39SMark Brown if (!regmap_debugfs_root) { 128*31244e39SMark Brown pr_warn("regmap: Failed to create debugfs root\n"); 129*31244e39SMark Brown return; 130*31244e39SMark Brown } 131*31244e39SMark Brown } 132