aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base/regmap
diff options
context:
space:
mode:
authorMark Brown <broonie@linaro.org>2013-06-30 07:40:01 -0400
committerMark Brown <broonie@linaro.org>2013-06-30 07:40:01 -0400
commitfeff98f5507f98c0422252caec41c3be9e6b6399 (patch)
treed014206d6ecc095ceb8e03ea2b17b42bf1ce786a /drivers/base/regmap
parent9e895ace5d82df8929b16f58e9f515f6d54ab82d (diff)
parentd6814a7dafa590ec5fe0597922ea76354f9bec59 (diff)
Merge remote-tracking branch 'regmap/topic/cache' into regmap-next
Diffstat (limited to 'drivers/base/regmap')
-rw-r--r--drivers/base/regmap/internal.h2
-rw-r--r--drivers/base/regmap/regcache-rbtree.c62
-rw-r--r--drivers/base/regmap/regcache.c83
-rw-r--r--drivers/base/regmap/regmap-debugfs.c4
-rw-r--r--drivers/base/regmap/regmap.c21
5 files changed, 145 insertions, 27 deletions
diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h
index c130536e0ab0..ae23d8391aa0 100644
--- a/drivers/base/regmap/internal.h
+++ b/drivers/base/regmap/internal.h
@@ -52,6 +52,7 @@ struct regmap_async {
52struct regmap { 52struct regmap {
53 struct mutex mutex; 53 struct mutex mutex;
54 spinlock_t spinlock; 54 spinlock_t spinlock;
55 unsigned long spinlock_flags;
55 regmap_lock lock; 56 regmap_lock lock;
56 regmap_unlock unlock; 57 regmap_unlock unlock;
57 void *lock_arg; /* This is passed to lock/unlock functions */ 58 void *lock_arg; /* This is passed to lock/unlock functions */
@@ -148,6 +149,7 @@ struct regcache_ops {
148 int (*read)(struct regmap *map, unsigned int reg, unsigned int *value); 149 int (*read)(struct regmap *map, unsigned int reg, unsigned int *value);
149 int (*write)(struct regmap *map, unsigned int reg, unsigned int value); 150 int (*write)(struct regmap *map, unsigned int reg, unsigned int value);
150 int (*sync)(struct regmap *map, unsigned int min, unsigned int max); 151 int (*sync)(struct regmap *map, unsigned int min, unsigned int max);
152 int (*drop)(struct regmap *map, unsigned int min, unsigned int max);
151}; 153};
152 154
153bool regmap_writeable(struct regmap *map, unsigned int reg); 155bool regmap_writeable(struct regmap *map, unsigned int reg);
diff --git a/drivers/base/regmap/regcache-rbtree.c b/drivers/base/regmap/regcache-rbtree.c
index 02f490bad30f..5c1435c4e210 100644
--- a/drivers/base/regmap/regcache-rbtree.c
+++ b/drivers/base/regmap/regcache-rbtree.c
@@ -304,6 +304,48 @@ static int regcache_rbtree_insert_to_block(struct regmap *map,
304 return 0; 304 return 0;
305} 305}
306 306
307static struct regcache_rbtree_node *
308regcache_rbtree_node_alloc(struct regmap *map, unsigned int reg)
309{
310 struct regcache_rbtree_node *rbnode;
311 const struct regmap_range *range;
312 int i;
313
314 rbnode = kzalloc(sizeof(*rbnode), GFP_KERNEL);
315 if (!rbnode)
316 return NULL;
317
318 /* If there is a read table then use it to guess at an allocation */
319 if (map->rd_table) {
320 for (i = 0; i < map->rd_table->n_yes_ranges; i++) {
321 if (regmap_reg_in_range(reg,
322 &map->rd_table->yes_ranges[i]))
323 break;
324 }
325
326 if (i != map->rd_table->n_yes_ranges) {
327 range = &map->rd_table->yes_ranges[i];
328 rbnode->blklen = range->range_max - range->range_min
329 + 1;
330 rbnode->base_reg = range->range_min;
331 }
332 }
333
334 if (!rbnode->blklen) {
335 rbnode->blklen = sizeof(*rbnode);
336 rbnode->base_reg = reg;
337 }
338
339 rbnode->block = kmalloc(rbnode->blklen * map->cache_word_size,
340 GFP_KERNEL);
341 if (!rbnode->block) {
342 kfree(rbnode);
343 return NULL;
344 }
345
346 return rbnode;
347}
348
307static int regcache_rbtree_write(struct regmap *map, unsigned int reg, 349static int regcache_rbtree_write(struct regmap *map, unsigned int reg,
308 unsigned int value) 350 unsigned int value)
309{ 351{
@@ -354,23 +396,15 @@ static int regcache_rbtree_write(struct regmap *map, unsigned int reg,
354 return 0; 396 return 0;
355 } 397 }
356 } 398 }
357 /* we did not manage to find a place to insert it in an existing 399
358 * block so create a new rbnode with a single register in its block. 400 /* We did not manage to find a place to insert it in
359 * This block will get populated further if any other adjacent 401 * an existing block so create a new rbnode.
360 * registers get modified in the future.
361 */ 402 */
362 rbnode = kzalloc(sizeof *rbnode, GFP_KERNEL); 403 rbnode = regcache_rbtree_node_alloc(map, reg);
363 if (!rbnode) 404 if (!rbnode)
364 return -ENOMEM; 405 return -ENOMEM;
365 rbnode->blklen = sizeof(*rbnode); 406 regcache_rbtree_set_register(map, rbnode,
366 rbnode->base_reg = reg; 407 reg - rbnode->base_reg, value);
367 rbnode->block = kmalloc(rbnode->blklen * map->cache_word_size,
368 GFP_KERNEL);
369 if (!rbnode->block) {
370 kfree(rbnode);
371 return -ENOMEM;
372 }
373 regcache_rbtree_set_register(map, rbnode, 0, value);
374 regcache_rbtree_insert(map, &rbtree_ctx->root, rbnode); 408 regcache_rbtree_insert(map, &rbtree_ctx->root, rbnode);
375 rbtree_ctx->cached_rbnode = rbnode; 409 rbtree_ctx->cached_rbnode = rbnode;
376 } 410 }
diff --git a/drivers/base/regmap/regcache.c b/drivers/base/regmap/regcache.c
index 507ee2da0f6e..e69102696533 100644
--- a/drivers/base/regmap/regcache.c
+++ b/drivers/base/regmap/regcache.c
@@ -250,6 +250,38 @@ int regcache_write(struct regmap *map,
250 return 0; 250 return 0;
251} 251}
252 252
253static int regcache_default_sync(struct regmap *map, unsigned int min,
254 unsigned int max)
255{
256 unsigned int reg;
257
258 for (reg = min; reg <= max; reg++) {
259 unsigned int val;
260 int ret;
261
262 if (regmap_volatile(map, reg))
263 continue;
264
265 ret = regcache_read(map, reg, &val);
266 if (ret)
267 return ret;
268
269 /* Is this the hardware default? If so skip. */
270 ret = regcache_lookup_reg(map, reg);
271 if (ret >= 0 && val == map->reg_defaults[ret].def)
272 continue;
273
274 map->cache_bypass = 1;
275 ret = _regmap_write(map, reg, val);
276 map->cache_bypass = 0;
277 if (ret)
278 return ret;
279 dev_dbg(map->dev, "Synced register %#x, value %#x\n", reg, val);
280 }
281
282 return 0;
283}
284
253/** 285/**
254 * regcache_sync: Sync the register cache with the hardware. 286 * regcache_sync: Sync the register cache with the hardware.
255 * 287 *
@@ -268,7 +300,7 @@ int regcache_sync(struct regmap *map)
268 const char *name; 300 const char *name;
269 unsigned int bypass; 301 unsigned int bypass;
270 302
271 BUG_ON(!map->cache_ops || !map->cache_ops->sync); 303 BUG_ON(!map->cache_ops);
272 304
273 map->lock(map->lock_arg); 305 map->lock(map->lock_arg);
274 /* Remember the initial bypass state */ 306 /* Remember the initial bypass state */
@@ -297,7 +329,10 @@ int regcache_sync(struct regmap *map)
297 } 329 }
298 map->cache_bypass = 0; 330 map->cache_bypass = 0;
299 331
300 ret = map->cache_ops->sync(map, 0, map->max_register); 332 if (map->cache_ops->sync)
333 ret = map->cache_ops->sync(map, 0, map->max_register);
334 else
335 ret = regcache_default_sync(map, 0, map->max_register);
301 336
302 if (ret == 0) 337 if (ret == 0)
303 map->cache_dirty = false; 338 map->cache_dirty = false;
@@ -331,7 +366,7 @@ int regcache_sync_region(struct regmap *map, unsigned int min,
331 const char *name; 366 const char *name;
332 unsigned int bypass; 367 unsigned int bypass;
333 368
334 BUG_ON(!map->cache_ops || !map->cache_ops->sync); 369 BUG_ON(!map->cache_ops);
335 370
336 map->lock(map->lock_arg); 371 map->lock(map->lock_arg);
337 372
@@ -346,7 +381,10 @@ int regcache_sync_region(struct regmap *map, unsigned int min,
346 if (!map->cache_dirty) 381 if (!map->cache_dirty)
347 goto out; 382 goto out;
348 383
349 ret = map->cache_ops->sync(map, min, max); 384 if (map->cache_ops->sync)
385 ret = map->cache_ops->sync(map, min, max);
386 else
387 ret = regcache_default_sync(map, min, max);
350 388
351out: 389out:
352 trace_regcache_sync(map->dev, name, "stop region"); 390 trace_regcache_sync(map->dev, name, "stop region");
@@ -359,6 +397,43 @@ out:
359EXPORT_SYMBOL_GPL(regcache_sync_region); 397EXPORT_SYMBOL_GPL(regcache_sync_region);
360 398
361/** 399/**
400 * regcache_drop_region: Discard part of the register cache
401 *
402 * @map: map to operate on
403 * @min: first register to discard
404 * @max: last register to discard
405 *
406 * Discard part of the register cache.
407 *
408 * Return a negative value on failure, 0 on success.
409 */
410int regcache_drop_region(struct regmap *map, unsigned int min,
411 unsigned int max)
412{
413 unsigned int reg;
414 int ret = 0;
415
416 if (!map->cache_present && !(map->cache_ops && map->cache_ops->drop))
417 return -EINVAL;
418
419 map->lock(map->lock_arg);
420
421 trace_regcache_drop_region(map->dev, min, max);
422
423 if (map->cache_present)
424 for (reg = min; reg < max + 1; reg++)
425 clear_bit(reg, map->cache_present);
426
427 if (map->cache_ops && map->cache_ops->drop)
428 ret = map->cache_ops->drop(map, min, max);
429
430 map->unlock(map->lock_arg);
431
432 return ret;
433}
434EXPORT_SYMBOL_GPL(regcache_drop_region);
435
436/**
362 * regcache_cache_only: Put a register map into cache only mode 437 * regcache_cache_only: Put a register map into cache only mode
363 * 438 *
364 * @map: map to configure 439 * @map: map to configure
diff --git a/drivers/base/regmap/regmap-debugfs.c b/drivers/base/regmap/regmap-debugfs.c
index 975719bc3450..98ee9c79678d 100644
--- a/drivers/base/regmap/regmap-debugfs.c
+++ b/drivers/base/regmap/regmap-debugfs.c
@@ -84,6 +84,10 @@ static unsigned int regmap_debugfs_get_dump_start(struct regmap *map,
84 unsigned int fpos_offset; 84 unsigned int fpos_offset;
85 unsigned int reg_offset; 85 unsigned int reg_offset;
86 86
87 /* Suppress the cache if we're using a subrange */
88 if (from)
89 return from;
90
87 /* 91 /*
88 * If we don't have a cache build one so we don't have to do a 92 * If we don't have a cache build one so we don't have to do a
89 * linear scan each time. 93 * linear scan each time.
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
index a941dcfe7590..1a01553189b3 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -65,9 +65,8 @@ bool regmap_reg_in_ranges(unsigned int reg,
65} 65}
66EXPORT_SYMBOL_GPL(regmap_reg_in_ranges); 66EXPORT_SYMBOL_GPL(regmap_reg_in_ranges);
67 67
68static bool _regmap_check_range_table(struct regmap *map, 68bool regmap_check_range_table(struct regmap *map, unsigned int reg,
69 unsigned int reg, 69 const struct regmap_access_table *table)
70 const struct regmap_access_table *table)
71{ 70{
72 /* Check "no ranges" first */ 71 /* Check "no ranges" first */
73 if (regmap_reg_in_ranges(reg, table->no_ranges, table->n_no_ranges)) 72 if (regmap_reg_in_ranges(reg, table->no_ranges, table->n_no_ranges))
@@ -80,6 +79,7 @@ static bool _regmap_check_range_table(struct regmap *map,
80 return regmap_reg_in_ranges(reg, table->yes_ranges, 79 return regmap_reg_in_ranges(reg, table->yes_ranges,
81 table->n_yes_ranges); 80 table->n_yes_ranges);
82} 81}
82EXPORT_SYMBOL_GPL(regmap_check_range_table);
83 83
84bool regmap_writeable(struct regmap *map, unsigned int reg) 84bool regmap_writeable(struct regmap *map, unsigned int reg)
85{ 85{
@@ -90,7 +90,7 @@ bool regmap_writeable(struct regmap *map, unsigned int reg)
90 return map->writeable_reg(map->dev, reg); 90 return map->writeable_reg(map->dev, reg);
91 91
92 if (map->wr_table) 92 if (map->wr_table)
93 return _regmap_check_range_table(map, reg, map->wr_table); 93 return regmap_check_range_table(map, reg, map->wr_table);
94 94
95 return true; 95 return true;
96} 96}
@@ -107,7 +107,7 @@ bool regmap_readable(struct regmap *map, unsigned int reg)
107 return map->readable_reg(map->dev, reg); 107 return map->readable_reg(map->dev, reg);
108 108
109 if (map->rd_table) 109 if (map->rd_table)
110 return _regmap_check_range_table(map, reg, map->rd_table); 110 return regmap_check_range_table(map, reg, map->rd_table);
111 111
112 return true; 112 return true;
113} 113}
@@ -121,7 +121,7 @@ bool regmap_volatile(struct regmap *map, unsigned int reg)
121 return map->volatile_reg(map->dev, reg); 121 return map->volatile_reg(map->dev, reg);
122 122
123 if (map->volatile_table) 123 if (map->volatile_table)
124 return _regmap_check_range_table(map, reg, map->volatile_table); 124 return regmap_check_range_table(map, reg, map->volatile_table);
125 125
126 return true; 126 return true;
127} 127}
@@ -135,7 +135,7 @@ bool regmap_precious(struct regmap *map, unsigned int reg)
135 return map->precious_reg(map->dev, reg); 135 return map->precious_reg(map->dev, reg);
136 136
137 if (map->precious_table) 137 if (map->precious_table)
138 return _regmap_check_range_table(map, reg, map->precious_table); 138 return regmap_check_range_table(map, reg, map->precious_table);
139 139
140 return false; 140 return false;
141} 141}
@@ -302,13 +302,16 @@ static void regmap_unlock_mutex(void *__map)
302static void regmap_lock_spinlock(void *__map) 302static void regmap_lock_spinlock(void *__map)
303{ 303{
304 struct regmap *map = __map; 304 struct regmap *map = __map;
305 spin_lock(&map->spinlock); 305 unsigned long flags;
306
307 spin_lock_irqsave(&map->spinlock, flags);
308 map->spinlock_flags = flags;
306} 309}
307 310
308static void regmap_unlock_spinlock(void *__map) 311static void regmap_unlock_spinlock(void *__map)
309{ 312{
310 struct regmap *map = __map; 313 struct regmap *map = __map;
311 spin_unlock(&map->spinlock); 314 spin_unlock_irqrestore(&map->spinlock, map->spinlock_flags);
312} 315}
313 316
314static void dev_get_regmap_release(struct device *dev, void *res) 317static void dev_get_regmap_release(struct device *dev, void *res)