[go: nahoru, domu]

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(&regmap_debugfs_early_lock);
487a52eaeb1898bc0589888ee62de291aa278379004Tero Kristo		list_add(&node->link, &regmap_debugfs_early_list);
488a52eaeb1898bc0589888ee62de291aa278379004Tero Kristo		mutex_unlock(&regmap_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, &regmap_name_fops);
514f0c2319f9f196726ebe4d7508fd8fbd804988db3Dimitris Papastamos
515065b4c587557dcd3dc8d3ff1ba2b9ecc6e0c6668Dimitris Papastamos	debugfs_create_file("range", 0400, map->debugfs,
516065b4c587557dcd3dc8d3ff1ba2b9ecc6e0c6668Dimitris Papastamos			    map, &regmap_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, &regmap_map_fops);
528449e38427fe57a6120fecd1051981c89ee862b3dMark Brown		debugfs_create_file("access", 0400, map->debugfs,
529449e38427fe57a6120fecd1051981c89ee862b3dMark Brown				    map, &regmap_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					    &regmap_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(&regmap_debugfs_early_lock);
569a52eaeb1898bc0589888ee62de291aa278379004Tero Kristo		list_for_each_entry_safe(node, tmp, &regmap_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(&regmap_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(&regmap_debugfs_early_lock);
591a52eaeb1898bc0589888ee62de291aa278379004Tero Kristo	list_for_each_entry_safe(node, tmp, &regmap_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(&regmap_debugfs_early_lock);
59731244e396fa9e4854cfd6dfe305983e77802c156Mark Brown}
598