aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base/regmap/regcache.c
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 /drivers/base/regmap/regcache.c
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>
Diffstat (limited to 'drivers/base/regmap/regcache.c')
-rw-r--r--drivers/base/regmap/regcache.c304
1 files changed, 304 insertions, 0 deletions
diff --git a/drivers/base/regmap/regcache.c b/drivers/base/regmap/regcache.c
new file mode 100644
index 000000000000..9575e4c5f34a
--- /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}