131244e396fa9e4854cfd6dfe305983e77802c156Mark Brown/* 231244e396fa9e4854cfd6dfe305983e77802c156Mark Brown * Register map access API - debugfs 331244e396fa9e4854cfd6dfe305983e77802c156Mark Brown * 431244e396fa9e4854cfd6dfe305983e77802c156Mark Brown * Copyright 2011 Wolfson Microelectronics plc 531244e396fa9e4854cfd6dfe305983e77802c156Mark Brown * 631244e396fa9e4854cfd6dfe305983e77802c156Mark Brown * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> 731244e396fa9e4854cfd6dfe305983e77802c156Mark Brown * 831244e396fa9e4854cfd6dfe305983e77802c156Mark Brown * This program is free software; you can redistribute it and/or modify 931244e396fa9e4854cfd6dfe305983e77802c156Mark Brown * it under the terms of the GNU General Public License version 2 as 1031244e396fa9e4854cfd6dfe305983e77802c156Mark Brown * published by the Free Software Foundation. 1131244e396fa9e4854cfd6dfe305983e77802c156Mark Brown */ 1231244e396fa9e4854cfd6dfe305983e77802c156Mark Brown 1331244e396fa9e4854cfd6dfe305983e77802c156Mark Brown#include <linux/slab.h> 1431244e396fa9e4854cfd6dfe305983e77802c156Mark Brown#include <linux/mutex.h> 1531244e396fa9e4854cfd6dfe305983e77802c156Mark Brown#include <linux/debugfs.h> 1631244e396fa9e4854cfd6dfe305983e77802c156Mark Brown#include <linux/uaccess.h> 1751990e825431089747f8896244b5c17d3a6423f1Paul Gortmaker#include <linux/device.h> 18a52eaeb1898bc0589888ee62de291aa278379004Tero Kristo#include <linux/list.h> 1931244e396fa9e4854cfd6dfe305983e77802c156Mark Brown 2031244e396fa9e4854cfd6dfe305983e77802c156Mark Brown#include "internal.h" 2131244e396fa9e4854cfd6dfe305983e77802c156Mark Brown 22a52eaeb1898bc0589888ee62de291aa278379004Tero Kristostruct regmap_debugfs_node { 23a52eaeb1898bc0589888ee62de291aa278379004Tero Kristo struct regmap *map; 24a52eaeb1898bc0589888ee62de291aa278379004Tero Kristo const char *name; 25a52eaeb1898bc0589888ee62de291aa278379004Tero Kristo struct list_head link; 26a52eaeb1898bc0589888ee62de291aa278379004Tero Kristo}; 27a52eaeb1898bc0589888ee62de291aa278379004Tero Kristo 2831244e396fa9e4854cfd6dfe305983e77802c156Mark Brownstatic struct dentry *regmap_debugfs_root; 29a52eaeb1898bc0589888ee62de291aa278379004Tero Kristostatic LIST_HEAD(regmap_debugfs_early_list); 30a52eaeb1898bc0589888ee62de291aa278379004Tero Kristostatic DEFINE_MUTEX(regmap_debugfs_early_lock); 3131244e396fa9e4854cfd6dfe305983e77802c156Mark Brown 3221f555445676e5c7d30bb9b3487cb183d02e45e3Mark Brown/* Calculate the length of a fixed format */ 3321f555445676e5c7d30bb9b3487cb183d02e45e3Mark Brownstatic size_t regmap_calc_reg_len(int max_val, char *buf, size_t buf_size) 3421f555445676e5c7d30bb9b3487cb183d02e45e3Mark Brown{ 3521f555445676e5c7d30bb9b3487cb183d02e45e3Mark Brown snprintf(buf, buf_size, "%x", max_val); 3621f555445676e5c7d30bb9b3487cb183d02e45e3Mark Brown return strlen(buf); 3721f555445676e5c7d30bb9b3487cb183d02e45e3Mark Brown} 3821f555445676e5c7d30bb9b3487cb183d02e45e3Mark Brown 39f0c2319f9f196726ebe4d7508fd8fbd804988db3Dimitris Papastamosstatic ssize_t regmap_name_read_file(struct file *file, 40f0c2319f9f196726ebe4d7508fd8fbd804988db3Dimitris Papastamos char __user *user_buf, size_t count, 41f0c2319f9f196726ebe4d7508fd8fbd804988db3Dimitris Papastamos loff_t *ppos) 42f0c2319f9f196726ebe4d7508fd8fbd804988db3Dimitris Papastamos{ 43f0c2319f9f196726ebe4d7508fd8fbd804988db3Dimitris Papastamos struct regmap *map = file->private_data; 44f0c2319f9f196726ebe4d7508fd8fbd804988db3Dimitris Papastamos int ret; 45f0c2319f9f196726ebe4d7508fd8fbd804988db3Dimitris Papastamos char *buf; 46f0c2319f9f196726ebe4d7508fd8fbd804988db3Dimitris Papastamos 47f0c2319f9f196726ebe4d7508fd8fbd804988db3Dimitris Papastamos buf = kmalloc(PAGE_SIZE, GFP_KERNEL); 48f0c2319f9f196726ebe4d7508fd8fbd804988db3Dimitris Papastamos if (!buf) 49f0c2319f9f196726ebe4d7508fd8fbd804988db3Dimitris Papastamos return -ENOMEM; 50f0c2319f9f196726ebe4d7508fd8fbd804988db3Dimitris Papastamos 51f0c2319f9f196726ebe4d7508fd8fbd804988db3Dimitris Papastamos ret = snprintf(buf, PAGE_SIZE, "%s\n", map->dev->driver->name); 52f0c2319f9f196726ebe4d7508fd8fbd804988db3Dimitris Papastamos if (ret < 0) { 53f0c2319f9f196726ebe4d7508fd8fbd804988db3Dimitris Papastamos kfree(buf); 54f0c2319f9f196726ebe4d7508fd8fbd804988db3Dimitris Papastamos return ret; 55f0c2319f9f196726ebe4d7508fd8fbd804988db3Dimitris Papastamos } 56f0c2319f9f196726ebe4d7508fd8fbd804988db3Dimitris Papastamos 57f0c2319f9f196726ebe4d7508fd8fbd804988db3Dimitris Papastamos ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret); 58f0c2319f9f196726ebe4d7508fd8fbd804988db3Dimitris Papastamos kfree(buf); 59f0c2319f9f196726ebe4d7508fd8fbd804988db3Dimitris Papastamos return ret; 60f0c2319f9f196726ebe4d7508fd8fbd804988db3Dimitris Papastamos} 61f0c2319f9f196726ebe4d7508fd8fbd804988db3Dimitris Papastamos 62f0c2319f9f196726ebe4d7508fd8fbd804988db3Dimitris Papastamosstatic const struct file_operations regmap_name_fops = { 63234e340582901211f40d8c732afc49f0630ecf05Stephen Boyd .open = simple_open, 64f0c2319f9f196726ebe4d7508fd8fbd804988db3Dimitris Papastamos .read = regmap_name_read_file, 65f0c2319f9f196726ebe4d7508fd8fbd804988db3Dimitris Papastamos .llseek = default_llseek, 66f0c2319f9f196726ebe4d7508fd8fbd804988db3Dimitris Papastamos}; 67f0c2319f9f196726ebe4d7508fd8fbd804988db3Dimitris Papastamos 6895f971c745a343255744703dc4ae8d78508519ccMark Brownstatic void regmap_debugfs_free_dump_cache(struct regmap *map) 6995f971c745a343255744703dc4ae8d78508519ccMark Brown{ 7095f971c745a343255744703dc4ae8d78508519ccMark Brown struct regmap_debugfs_off_cache *c; 7195f971c745a343255744703dc4ae8d78508519ccMark Brown 7295f971c745a343255744703dc4ae8d78508519ccMark Brown while (!list_empty(&map->debugfs_off_cache)) { 7395f971c745a343255744703dc4ae8d78508519ccMark Brown c = list_first_entry(&map->debugfs_off_cache, 7495f971c745a343255744703dc4ae8d78508519ccMark Brown struct regmap_debugfs_off_cache, 7595f971c745a343255744703dc4ae8d78508519ccMark Brown list); 7695f971c745a343255744703dc4ae8d78508519ccMark Brown list_del(&c->list); 7795f971c745a343255744703dc4ae8d78508519ccMark Brown kfree(c); 7895f971c745a343255744703dc4ae8d78508519ccMark Brown } 7995f971c745a343255744703dc4ae8d78508519ccMark Brown} 8095f971c745a343255744703dc4ae8d78508519ccMark Brown 81afab2f7b21b042bcbffb1e82f78243382a122d70Mark Brown/* 82afab2f7b21b042bcbffb1e82f78243382a122d70Mark Brown * Work out where the start offset maps into register numbers, bearing 83afab2f7b21b042bcbffb1e82f78243382a122d70Mark Brown * in mind that we suppress hidden registers. 84afab2f7b21b042bcbffb1e82f78243382a122d70Mark Brown */ 85afab2f7b21b042bcbffb1e82f78243382a122d70Mark Brownstatic unsigned int regmap_debugfs_get_dump_start(struct regmap *map, 86afab2f7b21b042bcbffb1e82f78243382a122d70Mark Brown unsigned int base, 87afab2f7b21b042bcbffb1e82f78243382a122d70Mark Brown loff_t from, 88afab2f7b21b042bcbffb1e82f78243382a122d70Mark Brown loff_t *pos) 89afab2f7b21b042bcbffb1e82f78243382a122d70Mark Brown{ 905166b7c006eeb4f6becc0822974d8da259484ba1Mark Brown struct regmap_debugfs_off_cache *c = NULL; 915166b7c006eeb4f6becc0822974d8da259484ba1Mark Brown loff_t p = 0; 925166b7c006eeb4f6becc0822974d8da259484ba1Mark Brown unsigned int i, ret; 93c2c1ee66016a45477f58f0fd30907b1e959ca76bDimitris Papastamos unsigned int fpos_offset; 94c2c1ee66016a45477f58f0fd30907b1e959ca76bDimitris Papastamos unsigned int reg_offset; 955166b7c006eeb4f6becc0822974d8da259484ba1Mark Brown 96d6814a7dafa590ec5fe0597922ea76354f9bec59Mark Brown /* Suppress the cache if we're using a subrange */ 9726ee47411ae22caa07d3f3b63ca6d097cba6681bLars-Peter Clausen if (base) 9826ee47411ae22caa07d3f3b63ca6d097cba6681bLars-Peter Clausen return base; 99d6814a7dafa590ec5fe0597922ea76354f9bec59Mark Brown 1005166b7c006eeb4f6becc0822974d8da259484ba1Mark Brown /* 1015166b7c006eeb4f6becc0822974d8da259484ba1Mark Brown * If we don't have a cache build one so we don't have to do a 1025166b7c006eeb4f6becc0822974d8da259484ba1Mark Brown * linear scan each time. 1035166b7c006eeb4f6becc0822974d8da259484ba1Mark Brown */ 104065b4c587557dcd3dc8d3ff1ba2b9ecc6e0c6668Dimitris Papastamos mutex_lock(&map->cache_lock); 105480738de0e076d759a973be623fac195cb901b82Dimitris Papastamos i = base; 1065166b7c006eeb4f6becc0822974d8da259484ba1Mark Brown if (list_empty(&map->debugfs_off_cache)) { 107480738de0e076d759a973be623fac195cb901b82Dimitris Papastamos for (; i <= map->max_register; i += map->reg_stride) { 1085166b7c006eeb4f6becc0822974d8da259484ba1Mark Brown /* Skip unprinted registers, closing off cache entry */ 1095166b7c006eeb4f6becc0822974d8da259484ba1Mark Brown if (!regmap_readable(map, i) || 1105166b7c006eeb4f6becc0822974d8da259484ba1Mark Brown regmap_precious(map, i)) { 1115166b7c006eeb4f6becc0822974d8da259484ba1Mark Brown if (c) { 1125166b7c006eeb4f6becc0822974d8da259484ba1Mark Brown c->max = p - 1; 113480738de0e076d759a973be623fac195cb901b82Dimitris Papastamos c->max_reg = i - map->reg_stride; 1145166b7c006eeb4f6becc0822974d8da259484ba1Mark Brown list_add_tail(&c->list, 1155166b7c006eeb4f6becc0822974d8da259484ba1Mark Brown &map->debugfs_off_cache); 1165166b7c006eeb4f6becc0822974d8da259484ba1Mark Brown c = NULL; 1175166b7c006eeb4f6becc0822974d8da259484ba1Mark Brown } 1185166b7c006eeb4f6becc0822974d8da259484ba1Mark Brown 1195166b7c006eeb4f6becc0822974d8da259484ba1Mark Brown continue; 1205166b7c006eeb4f6becc0822974d8da259484ba1Mark Brown } 1215166b7c006eeb4f6becc0822974d8da259484ba1Mark Brown 1225166b7c006eeb4f6becc0822974d8da259484ba1Mark Brown /* No cache entry? Start a new one */ 1235166b7c006eeb4f6becc0822974d8da259484ba1Mark Brown if (!c) { 1245166b7c006eeb4f6becc0822974d8da259484ba1Mark Brown c = kzalloc(sizeof(*c), GFP_KERNEL); 12595f971c745a343255744703dc4ae8d78508519ccMark Brown if (!c) { 12695f971c745a343255744703dc4ae8d78508519ccMark Brown regmap_debugfs_free_dump_cache(map); 127065b4c587557dcd3dc8d3ff1ba2b9ecc6e0c6668Dimitris Papastamos mutex_unlock(&map->cache_lock); 12895f971c745a343255744703dc4ae8d78508519ccMark Brown return base; 12995f971c745a343255744703dc4ae8d78508519ccMark Brown } 1305166b7c006eeb4f6becc0822974d8da259484ba1Mark Brown c->min = p; 1315166b7c006eeb4f6becc0822974d8da259484ba1Mark Brown c->base_reg = i; 1325166b7c006eeb4f6becc0822974d8da259484ba1Mark Brown } 1335166b7c006eeb4f6becc0822974d8da259484ba1Mark Brown 1345166b7c006eeb4f6becc0822974d8da259484ba1Mark Brown p += map->debugfs_tot_len; 1355166b7c006eeb4f6becc0822974d8da259484ba1Mark Brown } 1365166b7c006eeb4f6becc0822974d8da259484ba1Mark Brown } 137afab2f7b21b042bcbffb1e82f78243382a122d70Mark Brown 138e8d6539c8a94b88fc7ca5d6bdd9eeb0e64b434e4Mark Brown /* Close the last entry off if we didn't scan beyond it */ 139e8d6539c8a94b88fc7ca5d6bdd9eeb0e64b434e4Mark Brown if (c) { 140e8d6539c8a94b88fc7ca5d6bdd9eeb0e64b434e4Mark Brown c->max = p - 1; 141480738de0e076d759a973be623fac195cb901b82Dimitris Papastamos c->max_reg = i - map->reg_stride; 142e8d6539c8a94b88fc7ca5d6bdd9eeb0e64b434e4Mark Brown list_add_tail(&c->list, 143e8d6539c8a94b88fc7ca5d6bdd9eeb0e64b434e4Mark Brown &map->debugfs_off_cache); 144e8d6539c8a94b88fc7ca5d6bdd9eeb0e64b434e4Mark Brown } 145e8d6539c8a94b88fc7ca5d6bdd9eeb0e64b434e4Mark Brown 1465bd9f4bb34c16b62725b9486a290c01b1fdfec1cMark Brown /* 1475bd9f4bb34c16b62725b9486a290c01b1fdfec1cMark Brown * This should never happen; we return above if we fail to 1485bd9f4bb34c16b62725b9486a290c01b1fdfec1cMark Brown * allocate and we should never be in this code if there are 1495bd9f4bb34c16b62725b9486a290c01b1fdfec1cMark Brown * no registers at all. 1505bd9f4bb34c16b62725b9486a290c01b1fdfec1cMark Brown */ 151a3471469bcba61f8f18ca4c267b0cdd90a61e035Russell King WARN_ON(list_empty(&map->debugfs_off_cache)); 152a3471469bcba61f8f18ca4c267b0cdd90a61e035Russell King ret = base; 1535bd9f4bb34c16b62725b9486a290c01b1fdfec1cMark Brown 154cf57d6071f0610c99856c006ac06eb98a151f485Dimitris Papastamos /* Find the relevant block:offset */ 1555166b7c006eeb4f6becc0822974d8da259484ba1Mark Brown list_for_each_entry(c, &map->debugfs_off_cache, list) { 1565a1d6d172bc8a3ecf29add6c84d047025cb71566Mark Brown if (from >= c->min && from <= c->max) { 157cf57d6071f0610c99856c006ac06eb98a151f485Dimitris Papastamos fpos_offset = from - c->min; 158cf57d6071f0610c99856c006ac06eb98a151f485Dimitris Papastamos reg_offset = fpos_offset / map->debugfs_tot_len; 159cf57d6071f0610c99856c006ac06eb98a151f485Dimitris Papastamos *pos = c->min + (reg_offset * map->debugfs_tot_len); 160065b4c587557dcd3dc8d3ff1ba2b9ecc6e0c6668Dimitris Papastamos mutex_unlock(&map->cache_lock); 161213fa5d9685b985e0c61a8db1883a3abf94b18d7Srinivas Kandagatla return c->base_reg + (reg_offset * map->reg_stride); 162afab2f7b21b042bcbffb1e82f78243382a122d70Mark Brown } 163afab2f7b21b042bcbffb1e82f78243382a122d70Mark Brown 164cf57d6071f0610c99856c006ac06eb98a151f485Dimitris Papastamos *pos = c->max; 165cf57d6071f0610c99856c006ac06eb98a151f485Dimitris Papastamos ret = c->max_reg; 166afab2f7b21b042bcbffb1e82f78243382a122d70Mark Brown } 167065b4c587557dcd3dc8d3ff1ba2b9ecc6e0c6668Dimitris Papastamos mutex_unlock(&map->cache_lock); 168afab2f7b21b042bcbffb1e82f78243382a122d70Mark Brown 1695166b7c006eeb4f6becc0822974d8da259484ba1Mark Brown return ret; 170afab2f7b21b042bcbffb1e82f78243382a122d70Mark Brown} 171afab2f7b21b042bcbffb1e82f78243382a122d70Mark Brown 1724dd7c5531d3b046574da39096b1a66c738aca102Dimitris Papastamosstatic inline void regmap_calc_tot_len(struct regmap *map, 1734dd7c5531d3b046574da39096b1a66c738aca102Dimitris Papastamos void *buf, size_t count) 1744dd7c5531d3b046574da39096b1a66c738aca102Dimitris Papastamos{ 1754dd7c5531d3b046574da39096b1a66c738aca102Dimitris Papastamos /* Calculate the length of a fixed format */ 1764dd7c5531d3b046574da39096b1a66c738aca102Dimitris Papastamos if (!map->debugfs_tot_len) { 1774dd7c5531d3b046574da39096b1a66c738aca102Dimitris Papastamos map->debugfs_reg_len = regmap_calc_reg_len(map->max_register, 1784dd7c5531d3b046574da39096b1a66c738aca102Dimitris Papastamos buf, count); 1794dd7c5531d3b046574da39096b1a66c738aca102Dimitris Papastamos map->debugfs_val_len = 2 * map->format.val_bytes; 1804dd7c5531d3b046574da39096b1a66c738aca102Dimitris Papastamos map->debugfs_tot_len = map->debugfs_reg_len + 1814dd7c5531d3b046574da39096b1a66c738aca102Dimitris Papastamos map->debugfs_val_len + 3; /* : \n */ 1824dd7c5531d3b046574da39096b1a66c738aca102Dimitris Papastamos } 1834dd7c5531d3b046574da39096b1a66c738aca102Dimitris Papastamos} 1844dd7c5531d3b046574da39096b1a66c738aca102Dimitris Papastamos 185bd9cc12f4a7e7389432bba0cae6970dfc28f423cMark Brownstatic ssize_t regmap_read_debugfs(struct regmap *map, unsigned int from, 186bd9cc12f4a7e7389432bba0cae6970dfc28f423cMark Brown unsigned int to, char __user *user_buf, 187bd9cc12f4a7e7389432bba0cae6970dfc28f423cMark Brown size_t count, loff_t *ppos) 18831244e396fa9e4854cfd6dfe305983e77802c156Mark Brown{ 18931244e396fa9e4854cfd6dfe305983e77802c156Mark Brown size_t buf_pos = 0; 190afab2f7b21b042bcbffb1e82f78243382a122d70Mark Brown loff_t p = *ppos; 19131244e396fa9e4854cfd6dfe305983e77802c156Mark Brown ssize_t ret; 19231244e396fa9e4854cfd6dfe305983e77802c156Mark Brown int i; 19331244e396fa9e4854cfd6dfe305983e77802c156Mark Brown char *buf; 194afab2f7b21b042bcbffb1e82f78243382a122d70Mark Brown unsigned int val, start_reg; 19531244e396fa9e4854cfd6dfe305983e77802c156Mark Brown 19631244e396fa9e4854cfd6dfe305983e77802c156Mark Brown if (*ppos < 0 || !count) 19731244e396fa9e4854cfd6dfe305983e77802c156Mark Brown return -EINVAL; 19831244e396fa9e4854cfd6dfe305983e77802c156Mark Brown 19931244e396fa9e4854cfd6dfe305983e77802c156Mark Brown buf = kmalloc(count, GFP_KERNEL); 20031244e396fa9e4854cfd6dfe305983e77802c156Mark Brown if (!buf) 20131244e396fa9e4854cfd6dfe305983e77802c156Mark Brown return -ENOMEM; 20231244e396fa9e4854cfd6dfe305983e77802c156Mark Brown 2034dd7c5531d3b046574da39096b1a66c738aca102Dimitris Papastamos regmap_calc_tot_len(map, buf, count); 20431244e396fa9e4854cfd6dfe305983e77802c156Mark Brown 205afab2f7b21b042bcbffb1e82f78243382a122d70Mark Brown /* Work out which register we're starting at */ 206afab2f7b21b042bcbffb1e82f78243382a122d70Mark Brown start_reg = regmap_debugfs_get_dump_start(map, from, *ppos, &p); 207afab2f7b21b042bcbffb1e82f78243382a122d70Mark Brown 208afab2f7b21b042bcbffb1e82f78243382a122d70Mark Brown for (i = start_reg; i <= to; i += map->reg_stride) { 2098de2f081ef8ee716663f916df9f2a7d015fa0dadMark Brown if (!regmap_readable(map, i)) 21031244e396fa9e4854cfd6dfe305983e77802c156Mark Brown continue; 21131244e396fa9e4854cfd6dfe305983e77802c156Mark Brown 2128de2f081ef8ee716663f916df9f2a7d015fa0dadMark Brown if (regmap_precious(map, i)) 2132efe1642b73e74604498175de032b8a604868fb7Mark Brown continue; 2142efe1642b73e74604498175de032b8a604868fb7Mark Brown 21531244e396fa9e4854cfd6dfe305983e77802c156Mark Brown /* If we're in the region the user is trying to read */ 21631244e396fa9e4854cfd6dfe305983e77802c156Mark Brown if (p >= *ppos) { 21731244e396fa9e4854cfd6dfe305983e77802c156Mark Brown /* ...but not beyond it */ 218f3eb83994cb4c172ce5028b5ae7ea08462cc3f1dDimitris Papastamos if (buf_pos + map->debugfs_tot_len > count) 21931244e396fa9e4854cfd6dfe305983e77802c156Mark Brown break; 22031244e396fa9e4854cfd6dfe305983e77802c156Mark Brown 22131244e396fa9e4854cfd6dfe305983e77802c156Mark Brown /* Format the register */ 22231244e396fa9e4854cfd6dfe305983e77802c156Mark Brown snprintf(buf + buf_pos, count - buf_pos, "%.*x: ", 223cbc1938badc31f43ab77e92a9b1a51c4fe8b4113Mark Brown map->debugfs_reg_len, i - from); 224cbc1938badc31f43ab77e92a9b1a51c4fe8b4113Mark Brown buf_pos += map->debugfs_reg_len + 2; 22531244e396fa9e4854cfd6dfe305983e77802c156Mark Brown 22631244e396fa9e4854cfd6dfe305983e77802c156Mark Brown /* Format the value, write all X if we can't read */ 22731244e396fa9e4854cfd6dfe305983e77802c156Mark Brown ret = regmap_read(map, i, &val); 22831244e396fa9e4854cfd6dfe305983e77802c156Mark Brown if (ret == 0) 22931244e396fa9e4854cfd6dfe305983e77802c156Mark Brown snprintf(buf + buf_pos, count - buf_pos, 230cbc1938badc31f43ab77e92a9b1a51c4fe8b4113Mark Brown "%.*x", map->debugfs_val_len, val); 23131244e396fa9e4854cfd6dfe305983e77802c156Mark Brown else 232cbc1938badc31f43ab77e92a9b1a51c4fe8b4113Mark Brown memset(buf + buf_pos, 'X', 233cbc1938badc31f43ab77e92a9b1a51c4fe8b4113Mark Brown map->debugfs_val_len); 23431244e396fa9e4854cfd6dfe305983e77802c156Mark Brown buf_pos += 2 * map->format.val_bytes; 23531244e396fa9e4854cfd6dfe305983e77802c156Mark Brown 23631244e396fa9e4854cfd6dfe305983e77802c156Mark Brown buf[buf_pos++] = '\n'; 23731244e396fa9e4854cfd6dfe305983e77802c156Mark Brown } 238cbc1938badc31f43ab77e92a9b1a51c4fe8b4113Mark Brown p += map->debugfs_tot_len; 23931244e396fa9e4854cfd6dfe305983e77802c156Mark Brown } 24031244e396fa9e4854cfd6dfe305983e77802c156Mark Brown 24131244e396fa9e4854cfd6dfe305983e77802c156Mark Brown ret = buf_pos; 24231244e396fa9e4854cfd6dfe305983e77802c156Mark Brown 24331244e396fa9e4854cfd6dfe305983e77802c156Mark Brown if (copy_to_user(user_buf, buf, buf_pos)) { 24431244e396fa9e4854cfd6dfe305983e77802c156Mark Brown ret = -EFAULT; 24531244e396fa9e4854cfd6dfe305983e77802c156Mark Brown goto out; 24631244e396fa9e4854cfd6dfe305983e77802c156Mark Brown } 24731244e396fa9e4854cfd6dfe305983e77802c156Mark Brown 24831244e396fa9e4854cfd6dfe305983e77802c156Mark Brown *ppos += buf_pos; 24931244e396fa9e4854cfd6dfe305983e77802c156Mark Brown 25031244e396fa9e4854cfd6dfe305983e77802c156Mark Brownout: 25131244e396fa9e4854cfd6dfe305983e77802c156Mark Brown kfree(buf); 25231244e396fa9e4854cfd6dfe305983e77802c156Mark Brown return ret; 25331244e396fa9e4854cfd6dfe305983e77802c156Mark Brown} 25431244e396fa9e4854cfd6dfe305983e77802c156Mark Brown 255bd9cc12f4a7e7389432bba0cae6970dfc28f423cMark Brownstatic ssize_t regmap_map_read_file(struct file *file, char __user *user_buf, 256bd9cc12f4a7e7389432bba0cae6970dfc28f423cMark Brown size_t count, loff_t *ppos) 257bd9cc12f4a7e7389432bba0cae6970dfc28f423cMark Brown{ 258bd9cc12f4a7e7389432bba0cae6970dfc28f423cMark Brown struct regmap *map = file->private_data; 259bd9cc12f4a7e7389432bba0cae6970dfc28f423cMark Brown 260bd9cc12f4a7e7389432bba0cae6970dfc28f423cMark Brown return regmap_read_debugfs(map, 0, map->max_register, user_buf, 261bd9cc12f4a7e7389432bba0cae6970dfc28f423cMark Brown count, ppos); 262bd9cc12f4a7e7389432bba0cae6970dfc28f423cMark Brown} 263bd9cc12f4a7e7389432bba0cae6970dfc28f423cMark Brown 26409c6ecd394105c4864a0e409e181c9b1578c2a63Dimitris Papastamos#undef REGMAP_ALLOW_WRITE_DEBUGFS 26509c6ecd394105c4864a0e409e181c9b1578c2a63Dimitris Papastamos#ifdef REGMAP_ALLOW_WRITE_DEBUGFS 26609c6ecd394105c4864a0e409e181c9b1578c2a63Dimitris Papastamos/* 26709c6ecd394105c4864a0e409e181c9b1578c2a63Dimitris Papastamos * This can be dangerous especially when we have clients such as 26809c6ecd394105c4864a0e409e181c9b1578c2a63Dimitris Papastamos * PMICs, therefore don't provide any real compile time configuration option 26909c6ecd394105c4864a0e409e181c9b1578c2a63Dimitris Papastamos * for this feature, people who want to use this will need to modify 27009c6ecd394105c4864a0e409e181c9b1578c2a63Dimitris Papastamos * the source code directly. 27109c6ecd394105c4864a0e409e181c9b1578c2a63Dimitris Papastamos */ 27209c6ecd394105c4864a0e409e181c9b1578c2a63Dimitris Papastamosstatic ssize_t regmap_map_write_file(struct file *file, 27309c6ecd394105c4864a0e409e181c9b1578c2a63Dimitris Papastamos const char __user *user_buf, 27409c6ecd394105c4864a0e409e181c9b1578c2a63Dimitris Papastamos size_t count, loff_t *ppos) 27509c6ecd394105c4864a0e409e181c9b1578c2a63Dimitris Papastamos{ 27609c6ecd394105c4864a0e409e181c9b1578c2a63Dimitris Papastamos char buf[32]; 27709c6ecd394105c4864a0e409e181c9b1578c2a63Dimitris Papastamos size_t buf_size; 27809c6ecd394105c4864a0e409e181c9b1578c2a63Dimitris Papastamos char *start = buf; 27909c6ecd394105c4864a0e409e181c9b1578c2a63Dimitris Papastamos unsigned long reg, value; 28009c6ecd394105c4864a0e409e181c9b1578c2a63Dimitris Papastamos struct regmap *map = file->private_data; 28168e850d80df934b9c9c15d8a0956512cb3b6f1fcDimitris Papastamos int ret; 28209c6ecd394105c4864a0e409e181c9b1578c2a63Dimitris Papastamos 28309c6ecd394105c4864a0e409e181c9b1578c2a63Dimitris Papastamos buf_size = min(count, (sizeof(buf)-1)); 28409c6ecd394105c4864a0e409e181c9b1578c2a63Dimitris Papastamos if (copy_from_user(buf, user_buf, buf_size)) 28509c6ecd394105c4864a0e409e181c9b1578c2a63Dimitris Papastamos return -EFAULT; 28609c6ecd394105c4864a0e409e181c9b1578c2a63Dimitris Papastamos buf[buf_size] = 0; 28709c6ecd394105c4864a0e409e181c9b1578c2a63Dimitris Papastamos 28809c6ecd394105c4864a0e409e181c9b1578c2a63Dimitris Papastamos while (*start == ' ') 28909c6ecd394105c4864a0e409e181c9b1578c2a63Dimitris Papastamos start++; 29009c6ecd394105c4864a0e409e181c9b1578c2a63Dimitris Papastamos reg = simple_strtoul(start, &start, 16); 29109c6ecd394105c4864a0e409e181c9b1578c2a63Dimitris Papastamos while (*start == ' ') 29209c6ecd394105c4864a0e409e181c9b1578c2a63Dimitris Papastamos start++; 29334da5e6770ac06df770a0355b417155e6e84e263Jingoo Han if (kstrtoul(start, 16, &value)) 29409c6ecd394105c4864a0e409e181c9b1578c2a63Dimitris Papastamos return -EINVAL; 29509c6ecd394105c4864a0e409e181c9b1578c2a63Dimitris Papastamos 29609c6ecd394105c4864a0e409e181c9b1578c2a63Dimitris Papastamos /* Userspace has been fiddling around behind the kernel's back */ 297f9e464a566a1c3c9b71558e5523288b5432c3e3fMark Brown add_taint(TAINT_USER, LOCKDEP_STILL_OK); 29809c6ecd394105c4864a0e409e181c9b1578c2a63Dimitris Papastamos 29968e850d80df934b9c9c15d8a0956512cb3b6f1fcDimitris Papastamos ret = regmap_write(map, reg, value); 30068e850d80df934b9c9c15d8a0956512cb3b6f1fcDimitris Papastamos if (ret < 0) 30168e850d80df934b9c9c15d8a0956512cb3b6f1fcDimitris Papastamos return ret; 30209c6ecd394105c4864a0e409e181c9b1578c2a63Dimitris Papastamos return buf_size; 30309c6ecd394105c4864a0e409e181c9b1578c2a63Dimitris Papastamos} 30409c6ecd394105c4864a0e409e181c9b1578c2a63Dimitris Papastamos#else 30509c6ecd394105c4864a0e409e181c9b1578c2a63Dimitris Papastamos#define regmap_map_write_file NULL 30609c6ecd394105c4864a0e409e181c9b1578c2a63Dimitris Papastamos#endif 30709c6ecd394105c4864a0e409e181c9b1578c2a63Dimitris Papastamos 30831244e396fa9e4854cfd6dfe305983e77802c156Mark Brownstatic const struct file_operations regmap_map_fops = { 309234e340582901211f40d8c732afc49f0630ecf05Stephen Boyd .open = simple_open, 31031244e396fa9e4854cfd6dfe305983e77802c156Mark Brown .read = regmap_map_read_file, 31109c6ecd394105c4864a0e409e181c9b1578c2a63Dimitris Papastamos .write = regmap_map_write_file, 31231244e396fa9e4854cfd6dfe305983e77802c156Mark Brown .llseek = default_llseek, 31331244e396fa9e4854cfd6dfe305983e77802c156Mark Brown}; 31431244e396fa9e4854cfd6dfe305983e77802c156Mark Brown 3154b020b3f9ba2af8031c5c7d759fbafd234d1c390Mark Brownstatic ssize_t regmap_range_read_file(struct file *file, char __user *user_buf, 3164b020b3f9ba2af8031c5c7d759fbafd234d1c390Mark Brown size_t count, loff_t *ppos) 3174b020b3f9ba2af8031c5c7d759fbafd234d1c390Mark Brown{ 3184b020b3f9ba2af8031c5c7d759fbafd234d1c390Mark Brown struct regmap_range_node *range = file->private_data; 3194b020b3f9ba2af8031c5c7d759fbafd234d1c390Mark Brown struct regmap *map = range->map; 3204b020b3f9ba2af8031c5c7d759fbafd234d1c390Mark Brown 3214b020b3f9ba2af8031c5c7d759fbafd234d1c390Mark Brown return regmap_read_debugfs(map, range->range_min, range->range_max, 3224b020b3f9ba2af8031c5c7d759fbafd234d1c390Mark Brown user_buf, count, ppos); 3234b020b3f9ba2af8031c5c7d759fbafd234d1c390Mark Brown} 3244b020b3f9ba2af8031c5c7d759fbafd234d1c390Mark Brown 3254b020b3f9ba2af8031c5c7d759fbafd234d1c390Mark Brownstatic const struct file_operations regmap_range_fops = { 3264b020b3f9ba2af8031c5c7d759fbafd234d1c390Mark Brown .open = simple_open, 3274b020b3f9ba2af8031c5c7d759fbafd234d1c390Mark Brown .read = regmap_range_read_file, 3284b020b3f9ba2af8031c5c7d759fbafd234d1c390Mark Brown .llseek = default_llseek, 3294b020b3f9ba2af8031c5c7d759fbafd234d1c390Mark Brown}; 3304b020b3f9ba2af8031c5c7d759fbafd234d1c390Mark Brown 331065b4c587557dcd3dc8d3ff1ba2b9ecc6e0c6668Dimitris Papastamosstatic ssize_t regmap_reg_ranges_read_file(struct file *file, 332065b4c587557dcd3dc8d3ff1ba2b9ecc6e0c6668Dimitris Papastamos char __user *user_buf, size_t count, 333065b4c587557dcd3dc8d3ff1ba2b9ecc6e0c6668Dimitris Papastamos loff_t *ppos) 334065b4c587557dcd3dc8d3ff1ba2b9ecc6e0c6668Dimitris Papastamos{ 335065b4c587557dcd3dc8d3ff1ba2b9ecc6e0c6668Dimitris Papastamos struct regmap *map = file->private_data; 336065b4c587557dcd3dc8d3ff1ba2b9ecc6e0c6668Dimitris Papastamos struct regmap_debugfs_off_cache *c; 337065b4c587557dcd3dc8d3ff1ba2b9ecc6e0c6668Dimitris Papastamos loff_t p = 0; 338065b4c587557dcd3dc8d3ff1ba2b9ecc6e0c6668Dimitris Papastamos size_t buf_pos = 0; 339065b4c587557dcd3dc8d3ff1ba2b9ecc6e0c6668Dimitris Papastamos char *buf; 340065b4c587557dcd3dc8d3ff1ba2b9ecc6e0c6668Dimitris Papastamos char *entry; 341065b4c587557dcd3dc8d3ff1ba2b9ecc6e0c6668Dimitris Papastamos int ret; 342065b4c587557dcd3dc8d3ff1ba2b9ecc6e0c6668Dimitris Papastamos 343065b4c587557dcd3dc8d3ff1ba2b9ecc6e0c6668Dimitris Papastamos if (*ppos < 0 || !count) 344065b4c587557dcd3dc8d3ff1ba2b9ecc6e0c6668Dimitris Papastamos return -EINVAL; 345065b4c587557dcd3dc8d3ff1ba2b9ecc6e0c6668Dimitris Papastamos 346065b4c587557dcd3dc8d3ff1ba2b9ecc6e0c6668Dimitris Papastamos buf = kmalloc(count, GFP_KERNEL); 347065b4c587557dcd3dc8d3ff1ba2b9ecc6e0c6668Dimitris Papastamos if (!buf) 348065b4c587557dcd3dc8d3ff1ba2b9ecc6e0c6668Dimitris Papastamos return -ENOMEM; 349065b4c587557dcd3dc8d3ff1ba2b9ecc6e0c6668Dimitris Papastamos 350065b4c587557dcd3dc8d3ff1ba2b9ecc6e0c6668Dimitris Papastamos entry = kmalloc(PAGE_SIZE, GFP_KERNEL); 351065b4c587557dcd3dc8d3ff1ba2b9ecc6e0c6668Dimitris Papastamos if (!entry) { 352065b4c587557dcd3dc8d3ff1ba2b9ecc6e0c6668Dimitris Papastamos kfree(buf); 353065b4c587557dcd3dc8d3ff1ba2b9ecc6e0c6668Dimitris Papastamos return -ENOMEM; 354065b4c587557dcd3dc8d3ff1ba2b9ecc6e0c6668Dimitris Papastamos } 355065b4c587557dcd3dc8d3ff1ba2b9ecc6e0c6668Dimitris Papastamos 356065b4c587557dcd3dc8d3ff1ba2b9ecc6e0c6668Dimitris Papastamos /* While we are at it, build the register dump cache 357065b4c587557dcd3dc8d3ff1ba2b9ecc6e0c6668Dimitris Papastamos * now so the read() operation on the `registers' file 358065b4c587557dcd3dc8d3ff1ba2b9ecc6e0c6668Dimitris Papastamos * can benefit from using the cache. We do not care 359065b4c587557dcd3dc8d3ff1ba2b9ecc6e0c6668Dimitris Papastamos * about the file position information that is contained 360065b4c587557dcd3dc8d3ff1ba2b9ecc6e0c6668Dimitris Papastamos * in the cache, just about the actual register blocks */ 361065b4c587557dcd3dc8d3ff1ba2b9ecc6e0c6668Dimitris Papastamos regmap_calc_tot_len(map, buf, count); 362065b4c587557dcd3dc8d3ff1ba2b9ecc6e0c6668Dimitris Papastamos regmap_debugfs_get_dump_start(map, 0, *ppos, &p); 363065b4c587557dcd3dc8d3ff1ba2b9ecc6e0c6668Dimitris Papastamos 364065b4c587557dcd3dc8d3ff1ba2b9ecc6e0c6668Dimitris Papastamos /* Reset file pointer as the fixed-format of the `registers' 365065b4c587557dcd3dc8d3ff1ba2b9ecc6e0c6668Dimitris Papastamos * file is not compatible with the `range' file */ 366065b4c587557dcd3dc8d3ff1ba2b9ecc6e0c6668Dimitris Papastamos p = 0; 367065b4c587557dcd3dc8d3ff1ba2b9ecc6e0c6668Dimitris Papastamos mutex_lock(&map->cache_lock); 368065b4c587557dcd3dc8d3ff1ba2b9ecc6e0c6668Dimitris Papastamos list_for_each_entry(c, &map->debugfs_off_cache, list) { 369065b4c587557dcd3dc8d3ff1ba2b9ecc6e0c6668Dimitris Papastamos snprintf(entry, PAGE_SIZE, "%x-%x", 370065b4c587557dcd3dc8d3ff1ba2b9ecc6e0c6668Dimitris Papastamos c->base_reg, c->max_reg); 371065b4c587557dcd3dc8d3ff1ba2b9ecc6e0c6668Dimitris Papastamos if (p >= *ppos) { 372065b4c587557dcd3dc8d3ff1ba2b9ecc6e0c6668Dimitris Papastamos if (buf_pos + 1 + strlen(entry) > count) 373065b4c587557dcd3dc8d3ff1ba2b9ecc6e0c6668Dimitris Papastamos break; 374065b4c587557dcd3dc8d3ff1ba2b9ecc6e0c6668Dimitris Papastamos snprintf(buf + buf_pos, count - buf_pos, 375065b4c587557dcd3dc8d3ff1ba2b9ecc6e0c6668Dimitris Papastamos "%s", entry); 376065b4c587557dcd3dc8d3ff1ba2b9ecc6e0c6668Dimitris Papastamos buf_pos += strlen(entry); 377065b4c587557dcd3dc8d3ff1ba2b9ecc6e0c6668Dimitris Papastamos buf[buf_pos] = '\n'; 378065b4c587557dcd3dc8d3ff1ba2b9ecc6e0c6668Dimitris Papastamos buf_pos++; 379065b4c587557dcd3dc8d3ff1ba2b9ecc6e0c6668Dimitris Papastamos } 380065b4c587557dcd3dc8d3ff1ba2b9ecc6e0c6668Dimitris Papastamos p += strlen(entry) + 1; 381065b4c587557dcd3dc8d3ff1ba2b9ecc6e0c6668Dimitris Papastamos } 382065b4c587557dcd3dc8d3ff1ba2b9ecc6e0c6668Dimitris Papastamos mutex_unlock(&map->cache_lock); 383065b4c587557dcd3dc8d3ff1ba2b9ecc6e0c6668Dimitris Papastamos 384065b4c587557dcd3dc8d3ff1ba2b9ecc6e0c6668Dimitris Papastamos kfree(entry); 385065b4c587557dcd3dc8d3ff1ba2b9ecc6e0c6668Dimitris Papastamos ret = buf_pos; 386065b4c587557dcd3dc8d3ff1ba2b9ecc6e0c6668Dimitris Papastamos 387065b4c587557dcd3dc8d3ff1ba2b9ecc6e0c6668Dimitris Papastamos if (copy_to_user(user_buf, buf, buf_pos)) { 388065b4c587557dcd3dc8d3ff1ba2b9ecc6e0c6668Dimitris Papastamos ret = -EFAULT; 389065b4c587557dcd3dc8d3ff1ba2b9ecc6e0c6668Dimitris Papastamos goto out_buf; 390065b4c587557dcd3dc8d3ff1ba2b9ecc6e0c6668Dimitris Papastamos } 391065b4c587557dcd3dc8d3ff1ba2b9ecc6e0c6668Dimitris Papastamos 392065b4c587557dcd3dc8d3ff1ba2b9ecc6e0c6668Dimitris Papastamos *ppos += buf_pos; 393065b4c587557dcd3dc8d3ff1ba2b9ecc6e0c6668Dimitris Papastamosout_buf: 394065b4c587557dcd3dc8d3ff1ba2b9ecc6e0c6668Dimitris Papastamos kfree(buf); 395065b4c587557dcd3dc8d3ff1ba2b9ecc6e0c6668Dimitris Papastamos return ret; 396065b4c587557dcd3dc8d3ff1ba2b9ecc6e0c6668Dimitris Papastamos} 397065b4c587557dcd3dc8d3ff1ba2b9ecc6e0c6668Dimitris Papastamos 398065b4c587557dcd3dc8d3ff1ba2b9ecc6e0c6668Dimitris Papastamosstatic const struct file_operations regmap_reg_ranges_fops = { 399065b4c587557dcd3dc8d3ff1ba2b9ecc6e0c6668Dimitris Papastamos .open = simple_open, 400065b4c587557dcd3dc8d3ff1ba2b9ecc6e0c6668Dimitris Papastamos .read = regmap_reg_ranges_read_file, 401065b4c587557dcd3dc8d3ff1ba2b9ecc6e0c6668Dimitris Papastamos .llseek = default_llseek, 402065b4c587557dcd3dc8d3ff1ba2b9ecc6e0c6668Dimitris Papastamos}; 403065b4c587557dcd3dc8d3ff1ba2b9ecc6e0c6668Dimitris Papastamos 404449e38427fe57a6120fecd1051981c89ee862b3dMark Brownstatic ssize_t regmap_access_read_file(struct file *file, 405449e38427fe57a6120fecd1051981c89ee862b3dMark Brown char __user *user_buf, size_t count, 406449e38427fe57a6120fecd1051981c89ee862b3dMark Brown loff_t *ppos) 407449e38427fe57a6120fecd1051981c89ee862b3dMark Brown{ 408449e38427fe57a6120fecd1051981c89ee862b3dMark Brown int reg_len, tot_len; 409449e38427fe57a6120fecd1051981c89ee862b3dMark Brown size_t buf_pos = 0; 410449e38427fe57a6120fecd1051981c89ee862b3dMark Brown loff_t p = 0; 411449e38427fe57a6120fecd1051981c89ee862b3dMark Brown ssize_t ret; 412449e38427fe57a6120fecd1051981c89ee862b3dMark Brown int i; 413449e38427fe57a6120fecd1051981c89ee862b3dMark Brown struct regmap *map = file->private_data; 414449e38427fe57a6120fecd1051981c89ee862b3dMark Brown char *buf; 415449e38427fe57a6120fecd1051981c89ee862b3dMark Brown 416449e38427fe57a6120fecd1051981c89ee862b3dMark Brown if (*ppos < 0 || !count) 417449e38427fe57a6120fecd1051981c89ee862b3dMark Brown return -EINVAL; 418449e38427fe57a6120fecd1051981c89ee862b3dMark Brown 419449e38427fe57a6120fecd1051981c89ee862b3dMark Brown buf = kmalloc(count, GFP_KERNEL); 420449e38427fe57a6120fecd1051981c89ee862b3dMark Brown if (!buf) 421449e38427fe57a6120fecd1051981c89ee862b3dMark Brown return -ENOMEM; 422449e38427fe57a6120fecd1051981c89ee862b3dMark Brown 423449e38427fe57a6120fecd1051981c89ee862b3dMark Brown /* Calculate the length of a fixed format */ 424449e38427fe57a6120fecd1051981c89ee862b3dMark Brown reg_len = regmap_calc_reg_len(map->max_register, buf, count); 425449e38427fe57a6120fecd1051981c89ee862b3dMark Brown tot_len = reg_len + 10; /* ': R W V P\n' */ 426449e38427fe57a6120fecd1051981c89ee862b3dMark Brown 427f01ee60fffa4dc6c77122121233a793f7f696e67Stephen Warren for (i = 0; i <= map->max_register; i += map->reg_stride) { 428449e38427fe57a6120fecd1051981c89ee862b3dMark Brown /* Ignore registers which are neither readable nor writable */ 429449e38427fe57a6120fecd1051981c89ee862b3dMark Brown if (!regmap_readable(map, i) && !regmap_writeable(map, i)) 430449e38427fe57a6120fecd1051981c89ee862b3dMark Brown continue; 431449e38427fe57a6120fecd1051981c89ee862b3dMark Brown 432449e38427fe57a6120fecd1051981c89ee862b3dMark Brown /* If we're in the region the user is trying to read */ 433449e38427fe57a6120fecd1051981c89ee862b3dMark Brown if (p >= *ppos) { 434449e38427fe57a6120fecd1051981c89ee862b3dMark Brown /* ...but not beyond it */ 435449e38427fe57a6120fecd1051981c89ee862b3dMark Brown if (buf_pos >= count - 1 - tot_len) 436449e38427fe57a6120fecd1051981c89ee862b3dMark Brown break; 437449e38427fe57a6120fecd1051981c89ee862b3dMark Brown 438449e38427fe57a6120fecd1051981c89ee862b3dMark Brown /* Format the register */ 439449e38427fe57a6120fecd1051981c89ee862b3dMark Brown snprintf(buf + buf_pos, count - buf_pos, 440449e38427fe57a6120fecd1051981c89ee862b3dMark Brown "%.*x: %c %c %c %c\n", 441449e38427fe57a6120fecd1051981c89ee862b3dMark Brown reg_len, i, 442449e38427fe57a6120fecd1051981c89ee862b3dMark Brown regmap_readable(map, i) ? 'y' : 'n', 443449e38427fe57a6120fecd1051981c89ee862b3dMark Brown regmap_writeable(map, i) ? 'y' : 'n', 444449e38427fe57a6120fecd1051981c89ee862b3dMark Brown regmap_volatile(map, i) ? 'y' : 'n', 445449e38427fe57a6120fecd1051981c89ee862b3dMark Brown regmap_precious(map, i) ? 'y' : 'n'); 446449e38427fe57a6120fecd1051981c89ee862b3dMark Brown 447449e38427fe57a6120fecd1051981c89ee862b3dMark Brown buf_pos += tot_len; 448449e38427fe57a6120fecd1051981c89ee862b3dMark Brown } 449449e38427fe57a6120fecd1051981c89ee862b3dMark Brown p += tot_len; 450449e38427fe57a6120fecd1051981c89ee862b3dMark Brown } 451449e38427fe57a6120fecd1051981c89ee862b3dMark Brown 452449e38427fe57a6120fecd1051981c89ee862b3dMark Brown ret = buf_pos; 453449e38427fe57a6120fecd1051981c89ee862b3dMark Brown 454449e38427fe57a6120fecd1051981c89ee862b3dMark Brown if (copy_to_user(user_buf, buf, buf_pos)) { 455449e38427fe57a6120fecd1051981c89ee862b3dMark Brown ret = -EFAULT; 456449e38427fe57a6120fecd1051981c89ee862b3dMark Brown goto out; 457449e38427fe57a6120fecd1051981c89ee862b3dMark Brown } 458449e38427fe57a6120fecd1051981c89ee862b3dMark Brown 459449e38427fe57a6120fecd1051981c89ee862b3dMark Brown *ppos += buf_pos; 460449e38427fe57a6120fecd1051981c89ee862b3dMark Brown 461449e38427fe57a6120fecd1051981c89ee862b3dMark Brownout: 462449e38427fe57a6120fecd1051981c89ee862b3dMark Brown kfree(buf); 463449e38427fe57a6120fecd1051981c89ee862b3dMark Brown return ret; 464449e38427fe57a6120fecd1051981c89ee862b3dMark Brown} 465449e38427fe57a6120fecd1051981c89ee862b3dMark Brown 466449e38427fe57a6120fecd1051981c89ee862b3dMark Brownstatic const struct file_operations regmap_access_fops = { 467234e340582901211f40d8c732afc49f0630ecf05Stephen Boyd .open = simple_open, 468449e38427fe57a6120fecd1051981c89ee862b3dMark Brown .read = regmap_access_read_file, 469449e38427fe57a6120fecd1051981c89ee862b3dMark Brown .llseek = default_llseek, 470449e38427fe57a6120fecd1051981c89ee862b3dMark Brown}; 47131244e396fa9e4854cfd6dfe305983e77802c156Mark Brown 472d3c242e1f22f5dfed009296ee45ce896153f0b53Stephen Warrenvoid regmap_debugfs_init(struct regmap *map, const char *name) 47331244e396fa9e4854cfd6dfe305983e77802c156Mark Brown{ 4744b020b3f9ba2af8031c5c7d759fbafd234d1c390Mark Brown struct rb_node *next; 4754b020b3f9ba2af8031c5c7d759fbafd234d1c390Mark Brown struct regmap_range_node *range_node; 4762c98e0c1cc6b8e86f1978286c3d4e0769ee9d733Xiubo Li const char *devname = "dummy"; 4774b020b3f9ba2af8031c5c7d759fbafd234d1c390Mark Brown 478a52eaeb1898bc0589888ee62de291aa278379004Tero Kristo /* If we don't have the debugfs root yet, postpone init */ 479a52eaeb1898bc0589888ee62de291aa278379004Tero Kristo if (!regmap_debugfs_root) { 480a52eaeb1898bc0589888ee62de291aa278379004Tero Kristo struct regmap_debugfs_node *node; 481a52eaeb1898bc0589888ee62de291aa278379004Tero Kristo node = kzalloc(sizeof(*node), GFP_KERNEL); 482a52eaeb1898bc0589888ee62de291aa278379004Tero Kristo if (!node) 483a52eaeb1898bc0589888ee62de291aa278379004Tero Kristo return; 484a52eaeb1898bc0589888ee62de291aa278379004Tero Kristo node->map = map; 485a52eaeb1898bc0589888ee62de291aa278379004Tero Kristo node->name = name; 486a52eaeb1898bc0589888ee62de291aa278379004Tero Kristo mutex_lock(®map_debugfs_early_lock); 487a52eaeb1898bc0589888ee62de291aa278379004Tero Kristo list_add(&node->link, ®map_debugfs_early_list); 488a52eaeb1898bc0589888ee62de291aa278379004Tero Kristo mutex_unlock(®map_debugfs_early_lock); 489a52eaeb1898bc0589888ee62de291aa278379004Tero Kristo return; 490a52eaeb1898bc0589888ee62de291aa278379004Tero Kristo } 491a52eaeb1898bc0589888ee62de291aa278379004Tero Kristo 4925166b7c006eeb4f6becc0822974d8da259484ba1Mark Brown INIT_LIST_HEAD(&map->debugfs_off_cache); 493065b4c587557dcd3dc8d3ff1ba2b9ecc6e0c6668Dimitris Papastamos mutex_init(&map->cache_lock); 4945166b7c006eeb4f6becc0822974d8da259484ba1Mark Brown 4952c98e0c1cc6b8e86f1978286c3d4e0769ee9d733Xiubo Li if (map->dev) 4962c98e0c1cc6b8e86f1978286c3d4e0769ee9d733Xiubo Li devname = dev_name(map->dev); 4972c98e0c1cc6b8e86f1978286c3d4e0769ee9d733Xiubo Li 498d3c242e1f22f5dfed009296ee45ce896153f0b53Stephen Warren if (name) { 499d3c242e1f22f5dfed009296ee45ce896153f0b53Stephen Warren map->debugfs_name = kasprintf(GFP_KERNEL, "%s-%s", 5002c98e0c1cc6b8e86f1978286c3d4e0769ee9d733Xiubo Li devname, name); 501d3c242e1f22f5dfed009296ee45ce896153f0b53Stephen Warren name = map->debugfs_name; 502d3c242e1f22f5dfed009296ee45ce896153f0b53Stephen Warren } else { 5032c98e0c1cc6b8e86f1978286c3d4e0769ee9d733Xiubo Li name = devname; 504d3c242e1f22f5dfed009296ee45ce896153f0b53Stephen Warren } 505d3c242e1f22f5dfed009296ee45ce896153f0b53Stephen Warren 506d3c242e1f22f5dfed009296ee45ce896153f0b53Stephen Warren map->debugfs = debugfs_create_dir(name, regmap_debugfs_root); 50731244e396fa9e4854cfd6dfe305983e77802c156Mark Brown if (!map->debugfs) { 50831244e396fa9e4854cfd6dfe305983e77802c156Mark Brown dev_warn(map->dev, "Failed to create debugfs directory\n"); 50931244e396fa9e4854cfd6dfe305983e77802c156Mark Brown return; 51031244e396fa9e4854cfd6dfe305983e77802c156Mark Brown } 51131244e396fa9e4854cfd6dfe305983e77802c156Mark Brown 512f0c2319f9f196726ebe4d7508fd8fbd804988db3Dimitris Papastamos debugfs_create_file("name", 0400, map->debugfs, 513f0c2319f9f196726ebe4d7508fd8fbd804988db3Dimitris Papastamos map, ®map_name_fops); 514f0c2319f9f196726ebe4d7508fd8fbd804988db3Dimitris Papastamos 515065b4c587557dcd3dc8d3ff1ba2b9ecc6e0c6668Dimitris Papastamos debugfs_create_file("range", 0400, map->debugfs, 516065b4c587557dcd3dc8d3ff1ba2b9ecc6e0c6668Dimitris Papastamos map, ®map_reg_ranges_fops); 517065b4c587557dcd3dc8d3ff1ba2b9ecc6e0c6668Dimitris Papastamos 518676970da5cf6fec096945a8bbc19749089af57aaPawel Moll if (map->max_register || regmap_readable(map, 0)) { 519ffff7a12ace24c54220631b79abb02ab65780b5aMarkus Pargmann umode_t registers_mode; 520ffff7a12ace24c54220631b79abb02ab65780b5aMarkus Pargmann 521ffff7a12ace24c54220631b79abb02ab65780b5aMarkus Pargmann if (IS_ENABLED(REGMAP_ALLOW_WRITE_DEBUGFS)) 522ffff7a12ace24c54220631b79abb02ab65780b5aMarkus Pargmann registers_mode = 0600; 523ffff7a12ace24c54220631b79abb02ab65780b5aMarkus Pargmann else 524ffff7a12ace24c54220631b79abb02ab65780b5aMarkus Pargmann registers_mode = 0400; 525ffff7a12ace24c54220631b79abb02ab65780b5aMarkus Pargmann 526ffff7a12ace24c54220631b79abb02ab65780b5aMarkus Pargmann debugfs_create_file("registers", registers_mode, map->debugfs, 52731244e396fa9e4854cfd6dfe305983e77802c156Mark Brown map, ®map_map_fops); 528449e38427fe57a6120fecd1051981c89ee862b3dMark Brown debugfs_create_file("access", 0400, map->debugfs, 529449e38427fe57a6120fecd1051981c89ee862b3dMark Brown map, ®map_access_fops); 530449e38427fe57a6120fecd1051981c89ee862b3dMark Brown } 531028a01e601487b5991b70dba506dfe87d83543f6Mark Brown 532028a01e601487b5991b70dba506dfe87d83543f6Mark Brown if (map->cache_type) { 533028a01e601487b5991b70dba506dfe87d83543f6Mark Brown debugfs_create_bool("cache_only", 0400, map->debugfs, 534028a01e601487b5991b70dba506dfe87d83543f6Mark Brown &map->cache_only); 535028a01e601487b5991b70dba506dfe87d83543f6Mark Brown debugfs_create_bool("cache_dirty", 0400, map->debugfs, 536028a01e601487b5991b70dba506dfe87d83543f6Mark Brown &map->cache_dirty); 537028a01e601487b5991b70dba506dfe87d83543f6Mark Brown debugfs_create_bool("cache_bypass", 0400, map->debugfs, 538028a01e601487b5991b70dba506dfe87d83543f6Mark Brown &map->cache_bypass); 539028a01e601487b5991b70dba506dfe87d83543f6Mark Brown } 5404b020b3f9ba2af8031c5c7d759fbafd234d1c390Mark Brown 5414b020b3f9ba2af8031c5c7d759fbafd234d1c390Mark Brown next = rb_first(&map->range_tree); 5424b020b3f9ba2af8031c5c7d759fbafd234d1c390Mark Brown while (next) { 5434b020b3f9ba2af8031c5c7d759fbafd234d1c390Mark Brown range_node = rb_entry(next, struct regmap_range_node, node); 5444b020b3f9ba2af8031c5c7d759fbafd234d1c390Mark Brown 5454b020b3f9ba2af8031c5c7d759fbafd234d1c390Mark Brown if (range_node->name) 5464b020b3f9ba2af8031c5c7d759fbafd234d1c390Mark Brown debugfs_create_file(range_node->name, 0400, 5474b020b3f9ba2af8031c5c7d759fbafd234d1c390Mark Brown map->debugfs, range_node, 5484b020b3f9ba2af8031c5c7d759fbafd234d1c390Mark Brown ®map_range_fops); 5494b020b3f9ba2af8031c5c7d759fbafd234d1c390Mark Brown 5504b020b3f9ba2af8031c5c7d759fbafd234d1c390Mark Brown next = rb_next(&range_node->node); 5514b020b3f9ba2af8031c5c7d759fbafd234d1c390Mark Brown } 5525e0cbe78762b5f02986bf9e59a188dad2f6e0be1Lars-Peter Clausen 5535e0cbe78762b5f02986bf9e59a188dad2f6e0be1Lars-Peter Clausen if (map->cache_ops && map->cache_ops->debugfs_init) 5545e0cbe78762b5f02986bf9e59a188dad2f6e0be1Lars-Peter Clausen map->cache_ops->debugfs_init(map); 55531244e396fa9e4854cfd6dfe305983e77802c156Mark Brown} 55631244e396fa9e4854cfd6dfe305983e77802c156Mark Brown 55731244e396fa9e4854cfd6dfe305983e77802c156Mark Brownvoid regmap_debugfs_exit(struct regmap *map) 55831244e396fa9e4854cfd6dfe305983e77802c156Mark Brown{ 559a52eaeb1898bc0589888ee62de291aa278379004Tero Kristo if (map->debugfs) { 560a52eaeb1898bc0589888ee62de291aa278379004Tero Kristo debugfs_remove_recursive(map->debugfs); 561a52eaeb1898bc0589888ee62de291aa278379004Tero Kristo mutex_lock(&map->cache_lock); 562a52eaeb1898bc0589888ee62de291aa278379004Tero Kristo regmap_debugfs_free_dump_cache(map); 563a52eaeb1898bc0589888ee62de291aa278379004Tero Kristo mutex_unlock(&map->cache_lock); 564a52eaeb1898bc0589888ee62de291aa278379004Tero Kristo kfree(map->debugfs_name); 565a52eaeb1898bc0589888ee62de291aa278379004Tero Kristo } else { 566a52eaeb1898bc0589888ee62de291aa278379004Tero Kristo struct regmap_debugfs_node *node, *tmp; 567a52eaeb1898bc0589888ee62de291aa278379004Tero Kristo 568a52eaeb1898bc0589888ee62de291aa278379004Tero Kristo mutex_lock(®map_debugfs_early_lock); 569a52eaeb1898bc0589888ee62de291aa278379004Tero Kristo list_for_each_entry_safe(node, tmp, ®map_debugfs_early_list, 570a52eaeb1898bc0589888ee62de291aa278379004Tero Kristo link) { 571a52eaeb1898bc0589888ee62de291aa278379004Tero Kristo if (node->map == map) { 572a52eaeb1898bc0589888ee62de291aa278379004Tero Kristo list_del(&node->link); 573a52eaeb1898bc0589888ee62de291aa278379004Tero Kristo kfree(node); 574a52eaeb1898bc0589888ee62de291aa278379004Tero Kristo } 575a52eaeb1898bc0589888ee62de291aa278379004Tero Kristo } 576a52eaeb1898bc0589888ee62de291aa278379004Tero Kristo mutex_unlock(®map_debugfs_early_lock); 577a52eaeb1898bc0589888ee62de291aa278379004Tero Kristo } 57831244e396fa9e4854cfd6dfe305983e77802c156Mark Brown} 57931244e396fa9e4854cfd6dfe305983e77802c156Mark Brown 58031244e396fa9e4854cfd6dfe305983e77802c156Mark Brownvoid regmap_debugfs_initcall(void) 58131244e396fa9e4854cfd6dfe305983e77802c156Mark Brown{ 582a52eaeb1898bc0589888ee62de291aa278379004Tero Kristo struct regmap_debugfs_node *node, *tmp; 583a52eaeb1898bc0589888ee62de291aa278379004Tero Kristo 58431244e396fa9e4854cfd6dfe305983e77802c156Mark Brown regmap_debugfs_root = debugfs_create_dir("regmap", NULL); 58531244e396fa9e4854cfd6dfe305983e77802c156Mark Brown if (!regmap_debugfs_root) { 58631244e396fa9e4854cfd6dfe305983e77802c156Mark Brown pr_warn("regmap: Failed to create debugfs root\n"); 58731244e396fa9e4854cfd6dfe305983e77802c156Mark Brown return; 58831244e396fa9e4854cfd6dfe305983e77802c156Mark Brown } 589a52eaeb1898bc0589888ee62de291aa278379004Tero Kristo 590a52eaeb1898bc0589888ee62de291aa278379004Tero Kristo mutex_lock(®map_debugfs_early_lock); 591a52eaeb1898bc0589888ee62de291aa278379004Tero Kristo list_for_each_entry_safe(node, tmp, ®map_debugfs_early_list, link) { 592a52eaeb1898bc0589888ee62de291aa278379004Tero Kristo regmap_debugfs_init(node->map, node->name); 593a52eaeb1898bc0589888ee62de291aa278379004Tero Kristo list_del(&node->link); 594a52eaeb1898bc0589888ee62de291aa278379004Tero Kristo kfree(node); 595a52eaeb1898bc0589888ee62de291aa278379004Tero Kristo } 596a52eaeb1898bc0589888ee62de291aa278379004Tero Kristo mutex_unlock(®map_debugfs_early_lock); 59731244e396fa9e4854cfd6dfe305983e77802c156Mark Brown} 598