diff options
Diffstat (limited to 'drivers/base/regmap/regcache.c')
-rw-r--r-- | drivers/base/regmap/regcache.c | 87 |
1 files changed, 57 insertions, 30 deletions
diff --git a/drivers/base/regmap/regcache.c b/drivers/base/regmap/regcache.c index 666f6f5011dc..1ead66186b7c 100644 --- a/drivers/base/regmap/regcache.c +++ b/drivers/base/regmap/regcache.c | |||
@@ -19,7 +19,6 @@ | |||
19 | #include "internal.h" | 19 | #include "internal.h" |
20 | 20 | ||
21 | static const struct regcache_ops *cache_types[] = { | 21 | static const struct regcache_ops *cache_types[] = { |
22 | ®cache_indexed_ops, | ||
23 | ®cache_rbtree_ops, | 22 | ®cache_rbtree_ops, |
24 | ®cache_lzo_ops, | 23 | ®cache_lzo_ops, |
25 | }; | 24 | }; |
@@ -61,8 +60,10 @@ static int regcache_hw_init(struct regmap *map) | |||
61 | 60 | ||
62 | map->reg_defaults = kmalloc(count * sizeof(struct reg_default), | 61 | map->reg_defaults = kmalloc(count * sizeof(struct reg_default), |
63 | GFP_KERNEL); | 62 | GFP_KERNEL); |
64 | if (!map->reg_defaults) | 63 | if (!map->reg_defaults) { |
65 | return -ENOMEM; | 64 | ret = -ENOMEM; |
65 | goto err_free; | ||
66 | } | ||
66 | 67 | ||
67 | /* fill the reg_defaults */ | 68 | /* fill the reg_defaults */ |
68 | map->num_reg_defaults = count; | 69 | map->num_reg_defaults = count; |
@@ -77,9 +78,15 @@ static int regcache_hw_init(struct regmap *map) | |||
77 | } | 78 | } |
78 | 79 | ||
79 | return 0; | 80 | return 0; |
81 | |||
82 | err_free: | ||
83 | if (map->cache_free) | ||
84 | kfree(map->reg_defaults_raw); | ||
85 | |||
86 | return ret; | ||
80 | } | 87 | } |
81 | 88 | ||
82 | int regcache_init(struct regmap *map) | 89 | int regcache_init(struct regmap *map, const struct regmap_config *config) |
83 | { | 90 | { |
84 | int ret; | 91 | int ret; |
85 | int i; | 92 | int i; |
@@ -100,6 +107,12 @@ int regcache_init(struct regmap *map) | |||
100 | return -EINVAL; | 107 | return -EINVAL; |
101 | } | 108 | } |
102 | 109 | ||
110 | map->num_reg_defaults = config->num_reg_defaults; | ||
111 | map->num_reg_defaults_raw = config->num_reg_defaults_raw; | ||
112 | map->reg_defaults_raw = config->reg_defaults_raw; | ||
113 | map->cache_word_size = DIV_ROUND_UP(config->val_bits, 8); | ||
114 | map->cache_size_raw = map->cache_word_size * config->num_reg_defaults_raw; | ||
115 | |||
103 | map->cache = NULL; | 116 | map->cache = NULL; |
104 | map->cache_ops = cache_types[i]; | 117 | map->cache_ops = cache_types[i]; |
105 | 118 | ||
@@ -112,10 +125,10 @@ int regcache_init(struct regmap *map) | |||
112 | * won't vanish from under us. We'll need to make | 125 | * won't vanish from under us. We'll need to make |
113 | * a copy of it. | 126 | * a copy of it. |
114 | */ | 127 | */ |
115 | if (map->reg_defaults) { | 128 | if (config->reg_defaults) { |
116 | if (!map->num_reg_defaults) | 129 | if (!map->num_reg_defaults) |
117 | return -EINVAL; | 130 | return -EINVAL; |
118 | tmp_buf = kmemdup(map->reg_defaults, map->num_reg_defaults * | 131 | tmp_buf = kmemdup(config->reg_defaults, map->num_reg_defaults * |
119 | sizeof(struct reg_default), GFP_KERNEL); | 132 | sizeof(struct reg_default), GFP_KERNEL); |
120 | if (!tmp_buf) | 133 | if (!tmp_buf) |
121 | return -ENOMEM; | 134 | return -ENOMEM; |
@@ -136,9 +149,18 @@ int regcache_init(struct regmap *map) | |||
136 | if (map->cache_ops->init) { | 149 | if (map->cache_ops->init) { |
137 | dev_dbg(map->dev, "Initializing %s cache\n", | 150 | dev_dbg(map->dev, "Initializing %s cache\n", |
138 | map->cache_ops->name); | 151 | map->cache_ops->name); |
139 | return map->cache_ops->init(map); | 152 | ret = map->cache_ops->init(map); |
153 | if (ret) | ||
154 | goto err_free; | ||
140 | } | 155 | } |
141 | return 0; | 156 | return 0; |
157 | |||
158 | err_free: | ||
159 | kfree(map->reg_defaults); | ||
160 | if (map->cache_free) | ||
161 | kfree(map->reg_defaults_raw); | ||
162 | |||
163 | return ret; | ||
142 | } | 164 | } |
143 | 165 | ||
144 | void regcache_exit(struct regmap *map) | 166 | void regcache_exit(struct regmap *map) |
@@ -171,16 +193,21 @@ void regcache_exit(struct regmap *map) | |||
171 | int regcache_read(struct regmap *map, | 193 | int regcache_read(struct regmap *map, |
172 | unsigned int reg, unsigned int *value) | 194 | unsigned int reg, unsigned int *value) |
173 | { | 195 | { |
196 | int ret; | ||
197 | |||
174 | if (map->cache_type == REGCACHE_NONE) | 198 | if (map->cache_type == REGCACHE_NONE) |
175 | return -ENOSYS; | 199 | return -ENOSYS; |
176 | 200 | ||
177 | BUG_ON(!map->cache_ops); | 201 | BUG_ON(!map->cache_ops); |
178 | 202 | ||
179 | if (!regmap_readable(map, reg)) | 203 | if (!regmap_volatile(map, reg)) { |
180 | return -EIO; | 204 | ret = map->cache_ops->read(map, reg, value); |
181 | 205 | ||
182 | if (!regmap_volatile(map, reg)) | 206 | if (ret == 0) |
183 | return map->cache_ops->read(map, reg, value); | 207 | trace_regmap_reg_read_cache(map->dev, reg, *value); |
208 | |||
209 | return ret; | ||
210 | } | ||
184 | 211 | ||
185 | return -EINVAL; | 212 | return -EINVAL; |
186 | } | 213 | } |
@@ -241,6 +268,8 @@ int regcache_sync(struct regmap *map) | |||
241 | map->cache_ops->name); | 268 | map->cache_ops->name); |
242 | name = map->cache_ops->name; | 269 | name = map->cache_ops->name; |
243 | trace_regcache_sync(map->dev, name, "start"); | 270 | trace_regcache_sync(map->dev, name, "start"); |
271 | if (!map->cache_dirty) | ||
272 | goto out; | ||
244 | if (map->cache_ops->sync) { | 273 | if (map->cache_ops->sync) { |
245 | ret = map->cache_ops->sync(map); | 274 | ret = map->cache_ops->sync(map); |
246 | } else { | 275 | } else { |
@@ -291,6 +320,23 @@ void regcache_cache_only(struct regmap *map, bool enable) | |||
291 | EXPORT_SYMBOL_GPL(regcache_cache_only); | 320 | EXPORT_SYMBOL_GPL(regcache_cache_only); |
292 | 321 | ||
293 | /** | 322 | /** |
323 | * regcache_mark_dirty: Mark the register cache as dirty | ||
324 | * | ||
325 | * @map: map to mark | ||
326 | * | ||
327 | * Mark the register cache as dirty, for example due to the device | ||
328 | * having been powered down for suspend. If the cache is not marked | ||
329 | * as dirty then the cache sync will be suppressed. | ||
330 | */ | ||
331 | void regcache_mark_dirty(struct regmap *map) | ||
332 | { | ||
333 | mutex_lock(&map->lock); | ||
334 | map->cache_dirty = true; | ||
335 | mutex_unlock(&map->lock); | ||
336 | } | ||
337 | EXPORT_SYMBOL_GPL(regcache_mark_dirty); | ||
338 | |||
339 | /** | ||
294 | * regcache_cache_bypass: Put a register map into cache bypass mode | 340 | * regcache_cache_bypass: Put a register map into cache bypass mode |
295 | * | 341 | * |
296 | * @map: map to configure | 342 | * @map: map to configure |
@@ -381,22 +427,3 @@ int regcache_lookup_reg(struct regmap *map, unsigned int reg) | |||
381 | else | 427 | else |
382 | return -ENOENT; | 428 | return -ENOENT; |
383 | } | 429 | } |
384 | |||
385 | int regcache_insert_reg(struct regmap *map, unsigned int reg, | ||
386 | unsigned int val) | ||
387 | { | ||
388 | void *tmp; | ||
389 | |||
390 | tmp = krealloc(map->reg_defaults, | ||
391 | (map->num_reg_defaults + 1) * sizeof(struct reg_default), | ||
392 | GFP_KERNEL); | ||
393 | if (!tmp) | ||
394 | return -ENOMEM; | ||
395 | map->reg_defaults = tmp; | ||
396 | map->num_reg_defaults++; | ||
397 | map->reg_defaults[map->num_reg_defaults - 1].reg = reg; | ||
398 | map->reg_defaults[map->num_reg_defaults - 1].def = val; | ||
399 | sort(map->reg_defaults, map->num_reg_defaults, | ||
400 | sizeof(struct reg_default), regcache_default_cmp, NULL); | ||
401 | return 0; | ||
402 | } | ||