aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDimitris Papastamos <dp@opensource.wolfsonmicro.com>2011-09-19 09:34:00 -0400
committerMark Brown <broonie@opensource.wolfsonmicro.com>2011-09-19 14:06:31 -0400
commit9fabe24e9b1af84509b842731d2beaf85e66681e (patch)
tree6ff64e0b6f42775925fdb3d396adce620a64e6f6
parentb9fb3f3e77cbd536b245db023091e3b7423adeba (diff)
regmap: Introduce caching support
This patch introduces caching support for regmap. The regcache API has evolved essentially out of ASoC soc-cache so most of the actual caching types (except LZO) have been tested in the past. The purpose of regcache is to optimize in time and space the handling of register caches. Time optimization is achieved by not having to go over a slow bus like I2C to read the value of a register, instead it is cached locally in memory and can be retrieved faster. Regarding space optimization, some of the cache types are better at packing the caches, for e.g. the rbtree and the LZO caches. By doing this the sacrifice in time still wins over doing I2C transactions. Signed-off-by: Dimitris Papastamos <dp@opensource.wolfsonmicro.com> Tested-by: Lars-Peter Clausen <lars@metafoo.de> Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
-rw-r--r--drivers/base/regmap/Makefile2
-rw-r--r--drivers/base/regmap/internal.h52
-rw-r--r--drivers/base/regmap/regcache.c304
-rw-r--r--include/linux/regmap.h15
4 files changed, 371 insertions, 2 deletions
diff --git a/drivers/base/regmap/Makefile b/drivers/base/regmap/Makefile
index 057c13f66a6..2e103ea9a3a 100644
--- a/drivers/base/regmap/Makefile
+++ b/drivers/base/regmap/Makefile
@@ -1,4 +1,4 @@
1obj-$(CONFIG_REGMAP) += regmap.o 1obj-$(CONFIG_REGMAP) += regmap.o regcache.o
2obj-$(CONFIG_DEBUG_FS) += regmap-debugfs.o 2obj-$(CONFIG_DEBUG_FS) += regmap-debugfs.o
3obj-$(CONFIG_REGMAP_I2C) += regmap-i2c.o 3obj-$(CONFIG_REGMAP_I2C) += regmap-i2c.o
4obj-$(CONFIG_REGMAP_SPI) += regmap-spi.o 4obj-$(CONFIG_REGMAP_SPI) += regmap-spi.o
diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h
index a98493cde5c..615f5581d5d 100644
--- a/drivers/base/regmap/internal.h
+++ b/drivers/base/regmap/internal.h
@@ -17,6 +17,7 @@
17#include <linux/fs.h> 17#include <linux/fs.h>
18 18
19struct regmap; 19struct regmap;
20struct regcache_ops;
20 21
21struct regmap_format { 22struct regmap_format {
22 size_t buf_size; 23 size_t buf_size;
@@ -49,6 +50,40 @@ struct regmap {
49 50
50 u8 read_flag_mask; 51 u8 read_flag_mask;
51 u8 write_flag_mask; 52 u8 write_flag_mask;
53
54 /* regcache specific members */
55 const struct regcache_ops *cache_ops;
56 enum regcache_type cache_type;
57
58 /* number of bytes in reg_defaults_raw */
59 unsigned int cache_size_raw;
60 /* number of bytes per word in reg_defaults_raw */
61 unsigned int cache_word_size;
62 /* number of entries in reg_defaults */
63 unsigned int num_reg_defaults;
64 /* number of entries in reg_defaults_raw */
65 unsigned int num_reg_defaults_raw;
66
67 /* if set, only the cache is modified not the HW */
68 unsigned int cache_only:1;
69 /* if set, only the HW is modified not the cache */
70 unsigned int cache_bypass:1;
71 /* if set, remember to free reg_defaults_raw */
72 unsigned int cache_free:1;
73
74 struct reg_default *reg_defaults;
75 const void *reg_defaults_raw;
76 void *cache;
77};
78
79struct regcache_ops {
80 const char *name;
81 enum regcache_type type;
82 int (*init)(struct regmap *map);
83 int (*exit)(struct regmap *map);
84 int (*read)(struct regmap *map, unsigned int reg, unsigned int *value);
85 int (*write)(struct regmap *map, unsigned int reg, unsigned int value);
86 int (*sync)(struct regmap *map);
52}; 87};
53 88
54bool regmap_writeable(struct regmap *map, unsigned int reg); 89bool regmap_writeable(struct regmap *map, unsigned int reg);
@@ -66,4 +101,21 @@ static inline void regmap_debugfs_init(struct regmap *map) { }
66static inline void regmap_debugfs_exit(struct regmap *map) { } 101static inline void regmap_debugfs_exit(struct regmap *map) { }
67#endif 102#endif
68 103
104/* regcache core declarations */
105int regcache_init(struct regmap *map);
106void regcache_exit(struct regmap *map);
107int regcache_read(struct regmap *map,
108 unsigned int reg, unsigned int *value);
109int regcache_write(struct regmap *map,
110 unsigned int reg, unsigned int value);
111int regcache_sync(struct regmap *map);
112
113unsigned int regcache_get_val(const void *base, unsigned int idx,
114 unsigned int word_size);
115bool regcache_set_val(void *base, unsigned int idx,
116 unsigned int val, unsigned int word_size);
117int regcache_lookup_reg(struct regmap *map, unsigned int reg);
118int regcache_insert_reg(struct regmap *map, unsigned int reg,
119 unsigned int val);
120
69#endif 121#endif
diff --git a/drivers/base/regmap/regcache.c b/drivers/base/regmap/regcache.c
new file mode 100644
index 00000000000..9575e4c5f34
--- /dev/null
+++ b/drivers/base/regmap/regcache.c
@@ -0,0 +1,304 @@
1/*
2 * Register cache access API
3 *
4 * Copyright 2011 Wolfson Microelectronics plc
5 *
6 * Author: Dimitris Papastamos <dp@opensource.wolfsonmicro.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12
13#include <linux/slab.h>
14#include <trace/events/regmap.h>
15
16#include "internal.h"
17
18static const struct regcache_ops *cache_types[] = {
19};
20
21static int regcache_hw_init(struct regmap *map)
22{
23 int i, j;
24 int ret;
25 int count;
26 unsigned int val;
27 void *tmp_buf;
28
29 if (!map->num_reg_defaults_raw)
30 return -EINVAL;
31
32 if (!map->reg_defaults_raw) {
33 dev_warn(map->dev, "No cache defaults, reading back from HW\n");
34 tmp_buf = kmalloc(map->cache_size_raw, GFP_KERNEL);
35 if (!tmp_buf)
36 return -EINVAL;
37 ret = regmap_bulk_read(map, 0, tmp_buf,
38 map->num_reg_defaults_raw);
39 if (ret < 0) {
40 kfree(tmp_buf);
41 return ret;
42 }
43 map->reg_defaults_raw = tmp_buf;
44 map->cache_free = 1;
45 }
46
47 /* calculate the size of reg_defaults */
48 for (count = 0, i = 0; i < map->num_reg_defaults_raw; i++) {
49 val = regcache_get_val(map->reg_defaults_raw,
50 i, map->cache_word_size);
51 if (!val)
52 continue;
53 count++;
54 }
55
56 map->reg_defaults = kmalloc(count * sizeof(struct reg_default),
57 GFP_KERNEL);
58 if (!map->reg_defaults)
59 return -ENOMEM;
60
61 /* fill the reg_defaults */
62 map->num_reg_defaults = count;
63 for (i = 0, j = 0; i < map->num_reg_defaults_raw; i++) {
64 val = regcache_get_val(map->reg_defaults_raw,
65 i, map->cache_word_size);
66 if (!val)
67 continue;
68 map->reg_defaults[j].reg = i;
69 map->reg_defaults[j].def = val;
70 j++;
71 }
72
73 return 0;
74}
75
76int regcache_init(struct regmap *map)
77{
78 int ret;
79 int i;
80 void *tmp_buf;
81
82 if (map->cache_type == REGCACHE_NONE)
83 return 0;
84
85 for (i = 0; i < ARRAY_SIZE(cache_types); i++)
86 if (cache_types[i]->type == map->cache_type)
87 break;
88
89 if (i == ARRAY_SIZE(cache_types)) {
90 dev_err(map->dev, "Could not match compress type: %d\n",
91 map->cache_type);
92 return -EINVAL;
93 }
94
95 map->cache = NULL;
96 map->cache_ops = cache_types[i];
97
98 if (!map->cache_ops->read ||
99 !map->cache_ops->write ||
100 !map->cache_ops->name)
101 return -EINVAL;
102
103 /* We still need to ensure that the reg_defaults
104 * won't vanish from under us. We'll need to make
105 * a copy of it.
106 */
107 if (map->reg_defaults) {
108 if (!map->num_reg_defaults)
109 return -EINVAL;
110 tmp_buf = kmemdup(map->reg_defaults, map->num_reg_defaults *
111 sizeof(struct reg_default), GFP_KERNEL);
112 if (!tmp_buf)
113 return -ENOMEM;
114 map->reg_defaults = tmp_buf;
115 } else {
116 /* Some devices such as PMIC's don't have cache defaults,
117 * we cope with this by reading back the HW registers and
118 * crafting the cache defaults by hand.
119 */
120 ret = regcache_hw_init(map);
121 if (ret < 0)
122 return ret;
123 }
124
125 if (!map->max_register)
126 map->max_register = map->num_reg_defaults_raw;
127
128 if (map->cache_ops->init) {
129 dev_dbg(map->dev, "Initializing %s cache\n",
130 map->cache_ops->name);
131 return map->cache_ops->init(map);
132 }
133 return 0;
134}
135
136void regcache_exit(struct regmap *map)
137{
138 if (map->cache_type == REGCACHE_NONE)
139 return;
140
141 BUG_ON(!map->cache_ops);
142
143 kfree(map->reg_defaults);
144 if (map->cache_free)
145 kfree(map->reg_defaults_raw);
146
147 if (map->cache_ops->exit) {
148 dev_dbg(map->dev, "Destroying %s cache\n",
149 map->cache_ops->name);
150 map->cache_ops->exit(map);
151 }
152}
153
154/**
155 * regcache_read: Fetch the value of a given register from the cache.
156 *
157 * @map: map to configure.
158 * @reg: The register index.
159 * @value: The value to be returned.
160 *
161 * Return a negative value on failure, 0 on success.
162 */
163int regcache_read(struct regmap *map,
164 unsigned int reg, unsigned int *value)
165{
166 if (map->cache_type == REGCACHE_NONE)
167 return -ENOSYS;
168
169 BUG_ON(!map->cache_ops);
170
171 if (!regmap_readable(map, reg))
172 return -EIO;
173
174 if (!regmap_volatile(map, reg))
175 return map->cache_ops->read(map, reg, value);
176
177 return -EINVAL;
178}
179EXPORT_SYMBOL_GPL(regcache_read);
180
181/**
182 * regcache_write: Set the value of a given register in the cache.
183 *
184 * @map: map to configure.
185 * @reg: The register index.
186 * @value: The new register value.
187 *
188 * Return a negative value on failure, 0 on success.
189 */
190int regcache_write(struct regmap *map,
191 unsigned int reg, unsigned int value)
192{
193 if (map->cache_type == REGCACHE_NONE)
194 return 0;
195
196 BUG_ON(!map->cache_ops);
197
198 if (!regmap_writeable(map, reg))
199 return -EIO;
200
201 if (!regmap_volatile(map, reg))
202 return map->cache_ops->write(map, reg, value);
203
204 return 0;
205}
206EXPORT_SYMBOL_GPL(regcache_write);
207
208/**
209 * regcache_sync: Sync the register cache with the hardware.
210 *
211 * @map: map to configure.
212 *
213 * Any registers that should not be synced should be marked as
214 * volatile. In general drivers can choose not to use the provided
215 * syncing functionality if they so require.
216 *
217 * Return a negative value on failure, 0 on success.
218 */
219int regcache_sync(struct regmap *map)
220{
221 BUG_ON(!map->cache_ops);
222
223 if (map->cache_ops->sync) {
224 dev_dbg(map->dev, "Syncing %s cache\n",
225 map->cache_ops->name);
226 return map->cache_ops->sync(map);
227 }
228 return 0;
229}
230EXPORT_SYMBOL_GPL(regcache_sync);
231
232bool regcache_set_val(void *base, unsigned int idx,
233 unsigned int val, unsigned int word_size)
234{
235 switch (word_size) {
236 case 1: {
237 u8 *cache = base;
238 if (cache[idx] == val)
239 return true;
240 cache[idx] = val;
241 break;
242 }
243 case 2: {
244 u16 *cache = base;
245 if (cache[idx] == val)
246 return true;
247 cache[idx] = val;
248 break;
249 }
250 default:
251 BUG();
252 }
253 /* unreachable */
254 return false;
255}
256
257unsigned int regcache_get_val(const void *base, unsigned int idx,
258 unsigned int word_size)
259{
260 if (!base)
261 return -EINVAL;
262
263 switch (word_size) {
264 case 1: {
265 const u8 *cache = base;
266 return cache[idx];
267 }
268 case 2: {
269 const u16 *cache = base;
270 return cache[idx];
271 }
272 default:
273 BUG();
274 }
275 /* unreachable */
276 return -1;
277}
278
279int regcache_lookup_reg(struct regmap *map, unsigned int reg)
280{
281 unsigned int i;
282
283 for (i = 0; i < map->num_reg_defaults; i++)
284 if (map->reg_defaults[i].reg == reg)
285 return i;
286 return -1;
287}
288
289int regcache_insert_reg(struct regmap *map, unsigned int reg,
290 unsigned int val)
291{
292 void *tmp;
293
294 tmp = krealloc(map->reg_defaults,
295 (map->num_reg_defaults + 1) * sizeof(struct reg_default),
296 GFP_KERNEL);
297 if (!tmp)
298 return -ENOMEM;
299 map->reg_defaults = tmp;
300 map->num_reg_defaults++;
301 map->reg_defaults[map->num_reg_defaults - 1].reg = reg;
302 map->reg_defaults[map->num_reg_defaults - 1].def = val;
303 return 0;
304}
diff --git a/include/linux/regmap.h b/include/linux/regmap.h
index 18d4afaac16..9d802944929 100644
--- a/include/linux/regmap.h
+++ b/include/linux/regmap.h
@@ -20,6 +20,11 @@
20struct i2c_client; 20struct i2c_client;
21struct spi_device; 21struct spi_device;
22 22
23/* An enum of all the supported cache types */
24enum regcache_type {
25 REGCACHE_NONE,
26};
27
23/** 28/**
24 * Default value for a register. We use an array of structs rather 29 * Default value for a register. We use an array of structs rather
25 * than a simple array as many modern devices have very sparse 30 * than a simple array as many modern devices have very sparse
@@ -59,6 +64,11 @@ struct reg_default {
59 * @write_flag_mask: Mask to be set in the top byte of the register when doing 64 * @write_flag_mask: Mask to be set in the top byte of the register when doing
60 * a write. If both read_flag_mask and write_flag_mask are 65 * a write. If both read_flag_mask and write_flag_mask are
61 * empty the regmap_bus default masks are used. 66 * empty the regmap_bus default masks are used.
67 *
68 * @cache_type: The actual cache type.
69 * @reg_defaults_raw: Power on reset values for registers (for use with
70 * register cache support).
71 * @num_reg_defaults_raw: Number of elements in reg_defaults_raw.
62 */ 72 */
63struct regmap_config { 73struct regmap_config {
64 int reg_bits; 74 int reg_bits;
@@ -71,7 +81,10 @@ struct regmap_config {
71 81
72 unsigned int max_register; 82 unsigned int max_register;
73 struct reg_default *reg_defaults; 83 struct reg_default *reg_defaults;
74 int num_reg_defaults; 84 unsigned int num_reg_defaults;
85 enum regcache_type cache_type;
86 const void *reg_defaults_raw;
87 unsigned int num_reg_defaults_raw;
75 88
76 u8 read_flag_mask; 89 u8 read_flag_mask;
77 u8 write_flag_mask; 90 u8 write_flag_mask;