diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-04-29 19:31:26 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-04-29 19:31:26 -0400 |
commit | 7b053842b95914119f132fdac294fb2591b2e9a8 (patch) | |
tree | 9d17379a2ed7c8a3119489168adf695a44543960 | |
parent | 5415ba99c229105a6939a7f9effe21045b8b2e5b (diff) | |
parent | 38a817965d2d624b0db68f3bf5ae783ad7f2087a (diff) |
Merge tag 'regmap-v3.10' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap
Pull regmap updates from Mark Brown:
"In user visible terms just a couple of enhancements here, though there
was a moderate amount of refactoring required in order to support the
register cache sync performance improvements.
- Support for block and asynchronous I/O during register cache
syncing; this provides a use case dependant performance
improvement.
- Additional debugfs information on the memory consuption and
register set"
* tag 'regmap-v3.10' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap: (23 commits)
regmap: don't corrupt work buffer in _regmap_raw_write()
regmap: cache: Fix format specifier in dev_dbg
regmap: cache: Make regcache_sync_block_raw static
regmap: cache: Write consecutive registers in a single block write
regmap: cache: Split raw and non-raw syncs
regmap: cache: Factor out block sync
regmap: cache: Factor out reg_present support from rbtree cache
regmap: cache: Use raw I/O to sync rbtrees if we can
regmap: core: Provide regmap_can_raw_write() operation
regmap: cache: Provide a get address of value operation
regmap: Cut down on the average # of nodes in the rbtree cache
regmap: core: Make raw write available to regcache
regmap: core: Warn on invalid operation combinations
regmap: irq: Clarify error message when we fail to request primary IRQ
regmap: rbtree Expose total memory consumption in the rbtree debugfs entry
regmap: debugfs: Add a registers `range' file
regmap: debugfs: Simplify calculation of `c->max_reg'
regmap: cache: Store caches in native register format where possible
regmap: core: Split out in place value parsing
regmap: cache: Use regcache_get_value() to check if we updated
...
-rw-r--r-- | drivers/base/regmap/internal.h | 40 | ||||
-rw-r--r-- | drivers/base/regmap/regcache-lzo.c | 6 | ||||
-rw-r--r-- | drivers/base/regmap/regcache-rbtree.c | 100 | ||||
-rw-r--r-- | drivers/base/regmap/regcache.c | 196 | ||||
-rw-r--r-- | drivers/base/regmap/regmap-debugfs.c | 94 | ||||
-rw-r--r-- | drivers/base/regmap/regmap-irq.c | 3 | ||||
-rw-r--r-- | drivers/base/regmap/regmap.c | 92 | ||||
-rw-r--r-- | include/linux/regmap.h | 1 | ||||
-rw-r--r-- | include/trace/events/regmap.h | 48 |
9 files changed, 462 insertions, 118 deletions
diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h index 5a22bd33ce3d..c130536e0ab0 100644 --- a/drivers/base/regmap/internal.h +++ b/drivers/base/regmap/internal.h | |||
@@ -38,7 +38,8 @@ struct regmap_format { | |||
38 | unsigned int reg, unsigned int val); | 38 | unsigned int reg, unsigned int val); |
39 | void (*format_reg)(void *buf, unsigned int reg, unsigned int shift); | 39 | void (*format_reg)(void *buf, unsigned int reg, unsigned int shift); |
40 | void (*format_val)(void *buf, unsigned int val, unsigned int shift); | 40 | void (*format_val)(void *buf, unsigned int val, unsigned int shift); |
41 | unsigned int (*parse_val)(void *buf); | 41 | unsigned int (*parse_val)(const void *buf); |
42 | void (*parse_inplace)(void *buf); | ||
42 | }; | 43 | }; |
43 | 44 | ||
44 | struct regmap_async { | 45 | struct regmap_async { |
@@ -76,6 +77,7 @@ struct regmap { | |||
76 | unsigned int debugfs_tot_len; | 77 | unsigned int debugfs_tot_len; |
77 | 78 | ||
78 | struct list_head debugfs_off_cache; | 79 | struct list_head debugfs_off_cache; |
80 | struct mutex cache_lock; | ||
79 | #endif | 81 | #endif |
80 | 82 | ||
81 | unsigned int max_register; | 83 | unsigned int max_register; |
@@ -125,6 +127,9 @@ struct regmap { | |||
125 | void *cache; | 127 | void *cache; |
126 | u32 cache_dirty; | 128 | u32 cache_dirty; |
127 | 129 | ||
130 | unsigned long *cache_present; | ||
131 | unsigned int cache_present_nbits; | ||
132 | |||
128 | struct reg_default *patch; | 133 | struct reg_default *patch; |
129 | int patch_regs; | 134 | int patch_regs; |
130 | 135 | ||
@@ -187,12 +192,35 @@ int regcache_read(struct regmap *map, | |||
187 | int regcache_write(struct regmap *map, | 192 | int regcache_write(struct regmap *map, |
188 | unsigned int reg, unsigned int value); | 193 | unsigned int reg, unsigned int value); |
189 | int regcache_sync(struct regmap *map); | 194 | int regcache_sync(struct regmap *map); |
190 | 195 | int regcache_sync_block(struct regmap *map, void *block, | |
191 | unsigned int regcache_get_val(const void *base, unsigned int idx, | 196 | unsigned int block_base, unsigned int start, |
192 | unsigned int word_size); | 197 | unsigned int end); |
193 | bool regcache_set_val(void *base, unsigned int idx, | 198 | |
194 | unsigned int val, unsigned int word_size); | 199 | static inline const void *regcache_get_val_addr(struct regmap *map, |
200 | const void *base, | ||
201 | unsigned int idx) | ||
202 | { | ||
203 | return base + (map->cache_word_size * idx); | ||
204 | } | ||
205 | |||
206 | unsigned int regcache_get_val(struct regmap *map, const void *base, | ||
207 | unsigned int idx); | ||
208 | bool regcache_set_val(struct regmap *map, void *base, unsigned int idx, | ||
209 | unsigned int val); | ||
195 | int regcache_lookup_reg(struct regmap *map, unsigned int reg); | 210 | int regcache_lookup_reg(struct regmap *map, unsigned int reg); |
211 | int regcache_set_reg_present(struct regmap *map, unsigned int reg); | ||
212 | |||
213 | static inline bool regcache_reg_present(struct regmap *map, unsigned int reg) | ||
214 | { | ||
215 | if (!map->cache_present) | ||
216 | return true; | ||
217 | if (reg > map->cache_present_nbits) | ||
218 | return false; | ||
219 | return map->cache_present[BIT_WORD(reg)] & BIT_MASK(reg); | ||
220 | } | ||
221 | |||
222 | int _regmap_raw_write(struct regmap *map, unsigned int reg, | ||
223 | const void *val, size_t val_len, bool async); | ||
196 | 224 | ||
197 | void regmap_async_complete_cb(struct regmap_async *async, int ret); | 225 | void regmap_async_complete_cb(struct regmap_async *async, int ret); |
198 | 226 | ||
diff --git a/drivers/base/regmap/regcache-lzo.c b/drivers/base/regmap/regcache-lzo.c index afd6aa91a0df..e210a6d1406a 100644 --- a/drivers/base/regmap/regcache-lzo.c +++ b/drivers/base/regmap/regcache-lzo.c | |||
@@ -260,8 +260,7 @@ static int regcache_lzo_read(struct regmap *map, | |||
260 | ret = regcache_lzo_decompress_cache_block(map, lzo_block); | 260 | ret = regcache_lzo_decompress_cache_block(map, lzo_block); |
261 | if (ret >= 0) | 261 | if (ret >= 0) |
262 | /* fetch the value from the cache */ | 262 | /* fetch the value from the cache */ |
263 | *value = regcache_get_val(lzo_block->dst, blkpos, | 263 | *value = regcache_get_val(map, lzo_block->dst, blkpos); |
264 | map->cache_word_size); | ||
265 | 264 | ||
266 | kfree(lzo_block->dst); | 265 | kfree(lzo_block->dst); |
267 | /* restore the pointer and length of the compressed block */ | 266 | /* restore the pointer and length of the compressed block */ |
@@ -304,8 +303,7 @@ static int regcache_lzo_write(struct regmap *map, | |||
304 | } | 303 | } |
305 | 304 | ||
306 | /* write the new value to the cache */ | 305 | /* write the new value to the cache */ |
307 | if (regcache_set_val(lzo_block->dst, blkpos, value, | 306 | if (regcache_set_val(map, lzo_block->dst, blkpos, value)) { |
308 | map->cache_word_size)) { | ||
309 | kfree(lzo_block->dst); | 307 | kfree(lzo_block->dst); |
310 | goto out; | 308 | goto out; |
311 | } | 309 | } |
diff --git a/drivers/base/regmap/regcache-rbtree.c b/drivers/base/regmap/regcache-rbtree.c index 79f4fca9877a..aa0875f6f1b7 100644 --- a/drivers/base/regmap/regcache-rbtree.c +++ b/drivers/base/regmap/regcache-rbtree.c | |||
@@ -47,22 +47,21 @@ static inline void regcache_rbtree_get_base_top_reg( | |||
47 | *top = rbnode->base_reg + ((rbnode->blklen - 1) * map->reg_stride); | 47 | *top = rbnode->base_reg + ((rbnode->blklen - 1) * map->reg_stride); |
48 | } | 48 | } |
49 | 49 | ||
50 | static unsigned int regcache_rbtree_get_register( | 50 | static unsigned int regcache_rbtree_get_register(struct regmap *map, |
51 | struct regcache_rbtree_node *rbnode, unsigned int idx, | 51 | struct regcache_rbtree_node *rbnode, unsigned int idx) |
52 | unsigned int word_size) | ||
53 | { | 52 | { |
54 | return regcache_get_val(rbnode->block, idx, word_size); | 53 | return regcache_get_val(map, rbnode->block, idx); |
55 | } | 54 | } |
56 | 55 | ||
57 | static void regcache_rbtree_set_register(struct regcache_rbtree_node *rbnode, | 56 | static void regcache_rbtree_set_register(struct regmap *map, |
58 | unsigned int idx, unsigned int val, | 57 | struct regcache_rbtree_node *rbnode, |
59 | unsigned int word_size) | 58 | unsigned int idx, unsigned int val) |
60 | { | 59 | { |
61 | regcache_set_val(rbnode->block, idx, val, word_size); | 60 | regcache_set_val(map, rbnode->block, idx, val); |
62 | } | 61 | } |
63 | 62 | ||
64 | static struct regcache_rbtree_node *regcache_rbtree_lookup(struct regmap *map, | 63 | static struct regcache_rbtree_node *regcache_rbtree_lookup(struct regmap *map, |
65 | unsigned int reg) | 64 | unsigned int reg) |
66 | { | 65 | { |
67 | struct regcache_rbtree_ctx *rbtree_ctx = map->cache; | 66 | struct regcache_rbtree_ctx *rbtree_ctx = map->cache; |
68 | struct rb_node *node; | 67 | struct rb_node *node; |
@@ -139,15 +138,21 @@ static int rbtree_show(struct seq_file *s, void *ignored) | |||
139 | struct regcache_rbtree_node *n; | 138 | struct regcache_rbtree_node *n; |
140 | struct rb_node *node; | 139 | struct rb_node *node; |
141 | unsigned int base, top; | 140 | unsigned int base, top; |
141 | size_t mem_size; | ||
142 | int nodes = 0; | 142 | int nodes = 0; |
143 | int registers = 0; | 143 | int registers = 0; |
144 | int this_registers, average; | 144 | int this_registers, average; |
145 | 145 | ||
146 | map->lock(map); | 146 | map->lock(map); |
147 | 147 | ||
148 | mem_size = sizeof(*rbtree_ctx); | ||
149 | mem_size += BITS_TO_LONGS(map->cache_present_nbits) * sizeof(long); | ||
150 | |||
148 | for (node = rb_first(&rbtree_ctx->root); node != NULL; | 151 | for (node = rb_first(&rbtree_ctx->root); node != NULL; |
149 | node = rb_next(node)) { | 152 | node = rb_next(node)) { |
150 | n = container_of(node, struct regcache_rbtree_node, node); | 153 | n = container_of(node, struct regcache_rbtree_node, node); |
154 | mem_size += sizeof(*n); | ||
155 | mem_size += (n->blklen * map->cache_word_size); | ||
151 | 156 | ||
152 | regcache_rbtree_get_base_top_reg(map, n, &base, &top); | 157 | regcache_rbtree_get_base_top_reg(map, n, &base, &top); |
153 | this_registers = ((top - base) / map->reg_stride) + 1; | 158 | this_registers = ((top - base) / map->reg_stride) + 1; |
@@ -162,8 +167,8 @@ static int rbtree_show(struct seq_file *s, void *ignored) | |||
162 | else | 167 | else |
163 | average = 0; | 168 | average = 0; |
164 | 169 | ||
165 | seq_printf(s, "%d nodes, %d registers, average %d registers\n", | 170 | seq_printf(s, "%d nodes, %d registers, average %d registers, used %zu bytes\n", |
166 | nodes, registers, average); | 171 | nodes, registers, average, mem_size); |
167 | 172 | ||
168 | map->unlock(map); | 173 | map->unlock(map); |
169 | 174 | ||
@@ -260,8 +265,9 @@ static int regcache_rbtree_read(struct regmap *map, | |||
260 | rbnode = regcache_rbtree_lookup(map, reg); | 265 | rbnode = regcache_rbtree_lookup(map, reg); |
261 | if (rbnode) { | 266 | if (rbnode) { |
262 | reg_tmp = (reg - rbnode->base_reg) / map->reg_stride; | 267 | reg_tmp = (reg - rbnode->base_reg) / map->reg_stride; |
263 | *value = regcache_rbtree_get_register(rbnode, reg_tmp, | 268 | if (!regcache_reg_present(map, reg)) |
264 | map->cache_word_size); | 269 | return -ENOENT; |
270 | *value = regcache_rbtree_get_register(map, rbnode, reg_tmp); | ||
265 | } else { | 271 | } else { |
266 | return -ENOENT; | 272 | return -ENOENT; |
267 | } | 273 | } |
@@ -270,21 +276,23 @@ static int regcache_rbtree_read(struct regmap *map, | |||
270 | } | 276 | } |
271 | 277 | ||
272 | 278 | ||
273 | static int regcache_rbtree_insert_to_block(struct regcache_rbtree_node *rbnode, | 279 | static int regcache_rbtree_insert_to_block(struct regmap *map, |
280 | struct regcache_rbtree_node *rbnode, | ||
274 | unsigned int pos, unsigned int reg, | 281 | unsigned int pos, unsigned int reg, |
275 | unsigned int value, unsigned int word_size) | 282 | unsigned int value) |
276 | { | 283 | { |
277 | u8 *blk; | 284 | u8 *blk; |
278 | 285 | ||
279 | blk = krealloc(rbnode->block, | 286 | blk = krealloc(rbnode->block, |
280 | (rbnode->blklen + 1) * word_size, GFP_KERNEL); | 287 | (rbnode->blklen + 1) * map->cache_word_size, |
288 | GFP_KERNEL); | ||
281 | if (!blk) | 289 | if (!blk) |
282 | return -ENOMEM; | 290 | return -ENOMEM; |
283 | 291 | ||
284 | /* insert the register value in the correct place in the rbnode block */ | 292 | /* insert the register value in the correct place in the rbnode block */ |
285 | memmove(blk + (pos + 1) * word_size, | 293 | memmove(blk + (pos + 1) * map->cache_word_size, |
286 | blk + pos * word_size, | 294 | blk + pos * map->cache_word_size, |
287 | (rbnode->blklen - pos) * word_size); | 295 | (rbnode->blklen - pos) * map->cache_word_size); |
288 | 296 | ||
289 | /* update the rbnode block, its size and the base register */ | 297 | /* update the rbnode block, its size and the base register */ |
290 | rbnode->block = blk; | 298 | rbnode->block = blk; |
@@ -292,7 +300,7 @@ static int regcache_rbtree_insert_to_block(struct regcache_rbtree_node *rbnode, | |||
292 | if (!pos) | 300 | if (!pos) |
293 | rbnode->base_reg = reg; | 301 | rbnode->base_reg = reg; |
294 | 302 | ||
295 | regcache_rbtree_set_register(rbnode, pos, value, word_size); | 303 | regcache_rbtree_set_register(map, rbnode, pos, value); |
296 | return 0; | 304 | return 0; |
297 | } | 305 | } |
298 | 306 | ||
@@ -302,25 +310,24 @@ static int regcache_rbtree_write(struct regmap *map, unsigned int reg, | |||
302 | struct regcache_rbtree_ctx *rbtree_ctx; | 310 | struct regcache_rbtree_ctx *rbtree_ctx; |
303 | struct regcache_rbtree_node *rbnode, *rbnode_tmp; | 311 | struct regcache_rbtree_node *rbnode, *rbnode_tmp; |
304 | struct rb_node *node; | 312 | struct rb_node *node; |
305 | unsigned int val; | ||
306 | unsigned int reg_tmp; | 313 | unsigned int reg_tmp; |
307 | unsigned int pos; | 314 | unsigned int pos; |
308 | int i; | 315 | int i; |
309 | int ret; | 316 | int ret; |
310 | 317 | ||
311 | rbtree_ctx = map->cache; | 318 | rbtree_ctx = map->cache; |
319 | /* update the reg_present bitmap, make space if necessary */ | ||
320 | ret = regcache_set_reg_present(map, reg); | ||
321 | if (ret < 0) | ||
322 | return ret; | ||
323 | |||
312 | /* if we can't locate it in the cached rbnode we'll have | 324 | /* if we can't locate it in the cached rbnode we'll have |
313 | * to traverse the rbtree looking for it. | 325 | * to traverse the rbtree looking for it. |
314 | */ | 326 | */ |
315 | rbnode = regcache_rbtree_lookup(map, reg); | 327 | rbnode = regcache_rbtree_lookup(map, reg); |
316 | if (rbnode) { | 328 | if (rbnode) { |
317 | reg_tmp = (reg - rbnode->base_reg) / map->reg_stride; | 329 | reg_tmp = (reg - rbnode->base_reg) / map->reg_stride; |
318 | val = regcache_rbtree_get_register(rbnode, reg_tmp, | 330 | regcache_rbtree_set_register(map, rbnode, reg_tmp, value); |
319 | map->cache_word_size); | ||
320 | if (val == value) | ||
321 | return 0; | ||
322 | regcache_rbtree_set_register(rbnode, reg_tmp, value, | ||
323 | map->cache_word_size); | ||
324 | } else { | 331 | } else { |
325 | /* look for an adjacent register to the one we are about to add */ | 332 | /* look for an adjacent register to the one we are about to add */ |
326 | for (node = rb_first(&rbtree_ctx->root); node; | 333 | for (node = rb_first(&rbtree_ctx->root); node; |
@@ -337,9 +344,10 @@ static int regcache_rbtree_write(struct regmap *map, unsigned int reg, | |||
337 | pos = i + 1; | 344 | pos = i + 1; |
338 | else | 345 | else |
339 | pos = i; | 346 | pos = i; |
340 | ret = regcache_rbtree_insert_to_block(rbnode_tmp, pos, | 347 | ret = regcache_rbtree_insert_to_block(map, |
341 | reg, value, | 348 | rbnode_tmp, |
342 | map->cache_word_size); | 349 | pos, reg, |
350 | value); | ||
343 | if (ret) | 351 | if (ret) |
344 | return ret; | 352 | return ret; |
345 | rbtree_ctx->cached_rbnode = rbnode_tmp; | 353 | rbtree_ctx->cached_rbnode = rbnode_tmp; |
@@ -354,7 +362,7 @@ static int regcache_rbtree_write(struct regmap *map, unsigned int reg, | |||
354 | rbnode = kzalloc(sizeof *rbnode, GFP_KERNEL); | 362 | rbnode = kzalloc(sizeof *rbnode, GFP_KERNEL); |
355 | if (!rbnode) | 363 | if (!rbnode) |
356 | return -ENOMEM; | 364 | return -ENOMEM; |
357 | rbnode->blklen = 1; | 365 | rbnode->blklen = sizeof(*rbnode); |
358 | rbnode->base_reg = reg; | 366 | rbnode->base_reg = reg; |
359 | rbnode->block = kmalloc(rbnode->blklen * map->cache_word_size, | 367 | rbnode->block = kmalloc(rbnode->blklen * map->cache_word_size, |
360 | GFP_KERNEL); | 368 | GFP_KERNEL); |
@@ -362,7 +370,7 @@ static int regcache_rbtree_write(struct regmap *map, unsigned int reg, | |||
362 | kfree(rbnode); | 370 | kfree(rbnode); |
363 | return -ENOMEM; | 371 | return -ENOMEM; |
364 | } | 372 | } |
365 | regcache_rbtree_set_register(rbnode, 0, value, map->cache_word_size); | 373 | regcache_rbtree_set_register(map, rbnode, 0, value); |
366 | regcache_rbtree_insert(map, &rbtree_ctx->root, rbnode); | 374 | regcache_rbtree_insert(map, &rbtree_ctx->root, rbnode); |
367 | rbtree_ctx->cached_rbnode = rbnode; | 375 | rbtree_ctx->cached_rbnode = rbnode; |
368 | } | 376 | } |
@@ -376,10 +384,8 @@ static int regcache_rbtree_sync(struct regmap *map, unsigned int min, | |||
376 | struct regcache_rbtree_ctx *rbtree_ctx; | 384 | struct regcache_rbtree_ctx *rbtree_ctx; |
377 | struct rb_node *node; | 385 | struct rb_node *node; |
378 | struct regcache_rbtree_node *rbnode; | 386 | struct regcache_rbtree_node *rbnode; |
379 | unsigned int regtmp; | ||
380 | unsigned int val; | ||
381 | int ret; | 387 | int ret; |
382 | int i, base, end; | 388 | int base, end; |
383 | 389 | ||
384 | rbtree_ctx = map->cache; | 390 | rbtree_ctx = map->cache; |
385 | for (node = rb_first(&rbtree_ctx->root); node; node = rb_next(node)) { | 391 | for (node = rb_first(&rbtree_ctx->root); node; node = rb_next(node)) { |
@@ -402,27 +408,13 @@ static int regcache_rbtree_sync(struct regmap *map, unsigned int min, | |||
402 | else | 408 | else |
403 | end = rbnode->blklen; | 409 | end = rbnode->blklen; |
404 | 410 | ||
405 | for (i = base; i < end; i++) { | 411 | ret = regcache_sync_block(map, rbnode->block, rbnode->base_reg, |
406 | regtmp = rbnode->base_reg + (i * map->reg_stride); | 412 | base, end); |
407 | val = regcache_rbtree_get_register(rbnode, i, | 413 | if (ret != 0) |
408 | map->cache_word_size); | 414 | return ret; |
409 | |||
410 | /* Is this the hardware default? If so skip. */ | ||
411 | ret = regcache_lookup_reg(map, regtmp); | ||
412 | if (ret >= 0 && val == map->reg_defaults[ret].def) | ||
413 | continue; | ||
414 | |||
415 | map->cache_bypass = 1; | ||
416 | ret = _regmap_write(map, regtmp, val); | ||
417 | map->cache_bypass = 0; | ||
418 | if (ret) | ||
419 | return ret; | ||
420 | dev_dbg(map->dev, "Synced register %#x, value %#x\n", | ||
421 | regtmp, val); | ||
422 | } | ||
423 | } | 415 | } |
424 | 416 | ||
425 | return 0; | 417 | return regmap_async_complete(map); |
426 | } | 418 | } |
427 | 419 | ||
428 | struct regcache_ops regcache_rbtree_ops = { | 420 | struct regcache_ops regcache_rbtree_ops = { |
diff --git a/drivers/base/regmap/regcache.c b/drivers/base/regmap/regcache.c index e69ff3e4742c..75923f2396bd 100644 --- a/drivers/base/regmap/regcache.c +++ b/drivers/base/regmap/regcache.c | |||
@@ -45,8 +45,8 @@ static int regcache_hw_init(struct regmap *map) | |||
45 | tmp_buf = kmalloc(map->cache_size_raw, GFP_KERNEL); | 45 | tmp_buf = kmalloc(map->cache_size_raw, GFP_KERNEL); |
46 | if (!tmp_buf) | 46 | if (!tmp_buf) |
47 | return -EINVAL; | 47 | return -EINVAL; |
48 | ret = regmap_bulk_read(map, 0, tmp_buf, | 48 | ret = regmap_raw_read(map, 0, tmp_buf, |
49 | map->num_reg_defaults_raw); | 49 | map->num_reg_defaults_raw); |
50 | map->cache_bypass = cache_bypass; | 50 | map->cache_bypass = cache_bypass; |
51 | if (ret < 0) { | 51 | if (ret < 0) { |
52 | kfree(tmp_buf); | 52 | kfree(tmp_buf); |
@@ -58,8 +58,7 @@ static int regcache_hw_init(struct regmap *map) | |||
58 | 58 | ||
59 | /* calculate the size of reg_defaults */ | 59 | /* calculate the size of reg_defaults */ |
60 | for (count = 0, i = 0; i < map->num_reg_defaults_raw; i++) { | 60 | for (count = 0, i = 0; i < map->num_reg_defaults_raw; i++) { |
61 | val = regcache_get_val(map->reg_defaults_raw, | 61 | val = regcache_get_val(map, map->reg_defaults_raw, i); |
62 | i, map->cache_word_size); | ||
63 | if (regmap_volatile(map, i * map->reg_stride)) | 62 | if (regmap_volatile(map, i * map->reg_stride)) |
64 | continue; | 63 | continue; |
65 | count++; | 64 | count++; |
@@ -75,8 +74,7 @@ static int regcache_hw_init(struct regmap *map) | |||
75 | /* fill the reg_defaults */ | 74 | /* fill the reg_defaults */ |
76 | map->num_reg_defaults = count; | 75 | map->num_reg_defaults = count; |
77 | for (i = 0, j = 0; i < map->num_reg_defaults_raw; i++) { | 76 | for (i = 0, j = 0; i < map->num_reg_defaults_raw; i++) { |
78 | val = regcache_get_val(map->reg_defaults_raw, | 77 | val = regcache_get_val(map, map->reg_defaults_raw, i); |
79 | i, map->cache_word_size); | ||
80 | if (regmap_volatile(map, i * map->reg_stride)) | 78 | if (regmap_volatile(map, i * map->reg_stride)) |
81 | continue; | 79 | continue; |
82 | map->reg_defaults[j].reg = i * map->reg_stride; | 80 | map->reg_defaults[j].reg = i * map->reg_stride; |
@@ -123,6 +121,8 @@ int regcache_init(struct regmap *map, const struct regmap_config *config) | |||
123 | map->reg_defaults_raw = config->reg_defaults_raw; | 121 | map->reg_defaults_raw = config->reg_defaults_raw; |
124 | map->cache_word_size = DIV_ROUND_UP(config->val_bits, 8); | 122 | map->cache_word_size = DIV_ROUND_UP(config->val_bits, 8); |
125 | map->cache_size_raw = map->cache_word_size * config->num_reg_defaults_raw; | 123 | map->cache_size_raw = map->cache_word_size * config->num_reg_defaults_raw; |
124 | map->cache_present = NULL; | ||
125 | map->cache_present_nbits = 0; | ||
126 | 126 | ||
127 | map->cache = NULL; | 127 | map->cache = NULL; |
128 | map->cache_ops = cache_types[i]; | 128 | map->cache_ops = cache_types[i]; |
@@ -181,6 +181,7 @@ void regcache_exit(struct regmap *map) | |||
181 | 181 | ||
182 | BUG_ON(!map->cache_ops); | 182 | BUG_ON(!map->cache_ops); |
183 | 183 | ||
184 | kfree(map->cache_present); | ||
184 | kfree(map->reg_defaults); | 185 | kfree(map->reg_defaults); |
185 | if (map->cache_free) | 186 | if (map->cache_free) |
186 | kfree(map->reg_defaults_raw); | 187 | kfree(map->reg_defaults_raw); |
@@ -417,28 +418,68 @@ void regcache_cache_bypass(struct regmap *map, bool enable) | |||
417 | } | 418 | } |
418 | EXPORT_SYMBOL_GPL(regcache_cache_bypass); | 419 | EXPORT_SYMBOL_GPL(regcache_cache_bypass); |
419 | 420 | ||
420 | bool regcache_set_val(void *base, unsigned int idx, | 421 | int regcache_set_reg_present(struct regmap *map, unsigned int reg) |
421 | unsigned int val, unsigned int word_size) | ||
422 | { | 422 | { |
423 | switch (word_size) { | 423 | unsigned long *cache_present; |
424 | unsigned int cache_present_size; | ||
425 | unsigned int nregs; | ||
426 | int i; | ||
427 | |||
428 | nregs = reg + 1; | ||
429 | cache_present_size = BITS_TO_LONGS(nregs); | ||
430 | cache_present_size *= sizeof(long); | ||
431 | |||
432 | if (!map->cache_present) { | ||
433 | cache_present = kmalloc(cache_present_size, GFP_KERNEL); | ||
434 | if (!cache_present) | ||
435 | return -ENOMEM; | ||
436 | bitmap_zero(cache_present, nregs); | ||
437 | map->cache_present = cache_present; | ||
438 | map->cache_present_nbits = nregs; | ||
439 | } | ||
440 | |||
441 | if (nregs > map->cache_present_nbits) { | ||
442 | cache_present = krealloc(map->cache_present, | ||
443 | cache_present_size, GFP_KERNEL); | ||
444 | if (!cache_present) | ||
445 | return -ENOMEM; | ||
446 | for (i = 0; i < nregs; i++) | ||
447 | if (i >= map->cache_present_nbits) | ||
448 | clear_bit(i, cache_present); | ||
449 | map->cache_present = cache_present; | ||
450 | map->cache_present_nbits = nregs; | ||
451 | } | ||
452 | |||
453 | set_bit(reg, map->cache_present); | ||
454 | return 0; | ||
455 | } | ||
456 | |||
457 | bool regcache_set_val(struct regmap *map, void *base, unsigned int idx, | ||
458 | unsigned int val) | ||
459 | { | ||
460 | if (regcache_get_val(map, base, idx) == val) | ||
461 | return true; | ||
462 | |||
463 | /* Use device native format if possible */ | ||
464 | if (map->format.format_val) { | ||
465 | map->format.format_val(base + (map->cache_word_size * idx), | ||
466 | val, 0); | ||
467 | return false; | ||
468 | } | ||
469 | |||
470 | switch (map->cache_word_size) { | ||
424 | case 1: { | 471 | case 1: { |
425 | u8 *cache = base; | 472 | u8 *cache = base; |
426 | if (cache[idx] == val) | ||
427 | return true; | ||
428 | cache[idx] = val; | 473 | cache[idx] = val; |
429 | break; | 474 | break; |
430 | } | 475 | } |
431 | case 2: { | 476 | case 2: { |
432 | u16 *cache = base; | 477 | u16 *cache = base; |
433 | if (cache[idx] == val) | ||
434 | return true; | ||
435 | cache[idx] = val; | 478 | cache[idx] = val; |
436 | break; | 479 | break; |
437 | } | 480 | } |
438 | case 4: { | 481 | case 4: { |
439 | u32 *cache = base; | 482 | u32 *cache = base; |
440 | if (cache[idx] == val) | ||
441 | return true; | ||
442 | cache[idx] = val; | 483 | cache[idx] = val; |
443 | break; | 484 | break; |
444 | } | 485 | } |
@@ -448,13 +489,18 @@ bool regcache_set_val(void *base, unsigned int idx, | |||
448 | return false; | 489 | return false; |
449 | } | 490 | } |
450 | 491 | ||
451 | unsigned int regcache_get_val(const void *base, unsigned int idx, | 492 | unsigned int regcache_get_val(struct regmap *map, const void *base, |
452 | unsigned int word_size) | 493 | unsigned int idx) |
453 | { | 494 | { |
454 | if (!base) | 495 | if (!base) |
455 | return -EINVAL; | 496 | return -EINVAL; |
456 | 497 | ||
457 | switch (word_size) { | 498 | /* Use device native format if possible */ |
499 | if (map->format.parse_val) | ||
500 | return map->format.parse_val(regcache_get_val_addr(map, base, | ||
501 | idx)); | ||
502 | |||
503 | switch (map->cache_word_size) { | ||
458 | case 1: { | 504 | case 1: { |
459 | const u8 *cache = base; | 505 | const u8 *cache = base; |
460 | return cache[idx]; | 506 | return cache[idx]; |
@@ -498,3 +544,117 @@ int regcache_lookup_reg(struct regmap *map, unsigned int reg) | |||
498 | else | 544 | else |
499 | return -ENOENT; | 545 | return -ENOENT; |
500 | } | 546 | } |
547 | |||
548 | static int regcache_sync_block_single(struct regmap *map, void *block, | ||
549 | unsigned int block_base, | ||
550 | unsigned int start, unsigned int end) | ||
551 | { | ||
552 | unsigned int i, regtmp, val; | ||
553 | int ret; | ||
554 | |||
555 | for (i = start; i < end; i++) { | ||
556 | regtmp = block_base + (i * map->reg_stride); | ||
557 | |||
558 | if (!regcache_reg_present(map, regtmp)) | ||
559 | continue; | ||
560 | |||
561 | val = regcache_get_val(map, block, i); | ||
562 | |||
563 | /* Is this the hardware default? If so skip. */ | ||
564 | ret = regcache_lookup_reg(map, regtmp); | ||
565 | if (ret >= 0 && val == map->reg_defaults[ret].def) | ||
566 | continue; | ||
567 | |||
568 | map->cache_bypass = 1; | ||
569 | |||
570 | ret = _regmap_write(map, regtmp, val); | ||
571 | |||
572 | map->cache_bypass = 0; | ||
573 | if (ret != 0) | ||
574 | return ret; | ||
575 | dev_dbg(map->dev, "Synced register %#x, value %#x\n", | ||
576 | regtmp, val); | ||
577 | } | ||
578 | |||
579 | return 0; | ||
580 | } | ||
581 | |||
582 | static int regcache_sync_block_raw_flush(struct regmap *map, const void **data, | ||
583 | unsigned int base, unsigned int cur) | ||
584 | { | ||
585 | size_t val_bytes = map->format.val_bytes; | ||
586 | int ret, count; | ||
587 | |||
588 | if (*data == NULL) | ||
589 | return 0; | ||
590 | |||
591 | count = cur - base; | ||
592 | |||
593 | dev_dbg(map->dev, "Writing %zu bytes for %d registers from 0x%x-0x%x\n", | ||
594 | count * val_bytes, count, base, cur - 1); | ||
595 | |||
596 | map->cache_bypass = 1; | ||
597 | |||
598 | ret = _regmap_raw_write(map, base, *data, count * val_bytes, | ||
599 | false); | ||
600 | |||
601 | map->cache_bypass = 0; | ||
602 | |||
603 | *data = NULL; | ||
604 | |||
605 | return ret; | ||
606 | } | ||
607 | |||
608 | static int regcache_sync_block_raw(struct regmap *map, void *block, | ||
609 | unsigned int block_base, unsigned int start, | ||
610 | unsigned int end) | ||
611 | { | ||
612 | unsigned int i, val; | ||
613 | unsigned int regtmp = 0; | ||
614 | unsigned int base = 0; | ||
615 | const void *data = NULL; | ||
616 | int ret; | ||
617 | |||
618 | for (i = start; i < end; i++) { | ||
619 | regtmp = block_base + (i * map->reg_stride); | ||
620 | |||
621 | if (!regcache_reg_present(map, regtmp)) { | ||
622 | ret = regcache_sync_block_raw_flush(map, &data, | ||
623 | base, regtmp); | ||
624 | if (ret != 0) | ||
625 | return ret; | ||
626 | continue; | ||
627 | } | ||
628 | |||
629 | val = regcache_get_val(map, block, i); | ||
630 | |||
631 | /* Is this the hardware default? If so skip. */ | ||
632 | ret = regcache_lookup_reg(map, regtmp); | ||
633 | if (ret >= 0 && val == map->reg_defaults[ret].def) { | ||
634 | ret = regcache_sync_block_raw_flush(map, &data, | ||
635 | base, regtmp); | ||
636 | if (ret != 0) | ||
637 | return ret; | ||
638 | continue; | ||
639 | } | ||
640 | |||
641 | if (!data) { | ||
642 | data = regcache_get_val_addr(map, block, i); | ||
643 | base = regtmp; | ||
644 | } | ||
645 | } | ||
646 | |||
647 | return regcache_sync_block_raw_flush(map, &data, base, regtmp); | ||
648 | } | ||
649 | |||
650 | int regcache_sync_block(struct regmap *map, void *block, | ||
651 | unsigned int block_base, unsigned int start, | ||
652 | unsigned int end) | ||
653 | { | ||
654 | if (regmap_can_raw_write(map)) | ||
655 | return regcache_sync_block_raw(map, block, block_base, | ||
656 | start, end); | ||
657 | else | ||
658 | return regcache_sync_block_single(map, block, block_base, | ||
659 | start, end); | ||
660 | } | ||
diff --git a/drivers/base/regmap/regmap-debugfs.c b/drivers/base/regmap/regmap-debugfs.c index 81d6f605c92e..23b701f5fd2f 100644 --- a/drivers/base/regmap/regmap-debugfs.c +++ b/drivers/base/regmap/regmap-debugfs.c | |||
@@ -88,16 +88,16 @@ static unsigned int regmap_debugfs_get_dump_start(struct regmap *map, | |||
88 | * If we don't have a cache build one so we don't have to do a | 88 | * If we don't have a cache build one so we don't have to do a |
89 | * linear scan each time. | 89 | * linear scan each time. |
90 | */ | 90 | */ |
91 | mutex_lock(&map->cache_lock); | ||
92 | i = base; | ||
91 | if (list_empty(&map->debugfs_off_cache)) { | 93 | if (list_empty(&map->debugfs_off_cache)) { |
92 | for (i = base; i <= map->max_register; i += map->reg_stride) { | 94 | for (; i <= map->max_register; i += map->reg_stride) { |
93 | /* Skip unprinted registers, closing off cache entry */ | 95 | /* Skip unprinted registers, closing off cache entry */ |
94 | if (!regmap_readable(map, i) || | 96 | if (!regmap_readable(map, i) || |
95 | regmap_precious(map, i)) { | 97 | regmap_precious(map, i)) { |
96 | if (c) { | 98 | if (c) { |
97 | c->max = p - 1; | 99 | c->max = p - 1; |
98 | fpos_offset = c->max - c->min; | 100 | c->max_reg = i - map->reg_stride; |
99 | reg_offset = fpos_offset / map->debugfs_tot_len; | ||
100 | c->max_reg = c->base_reg + reg_offset; | ||
101 | list_add_tail(&c->list, | 101 | list_add_tail(&c->list, |
102 | &map->debugfs_off_cache); | 102 | &map->debugfs_off_cache); |
103 | c = NULL; | 103 | c = NULL; |
@@ -111,6 +111,7 @@ static unsigned int regmap_debugfs_get_dump_start(struct regmap *map, | |||
111 | c = kzalloc(sizeof(*c), GFP_KERNEL); | 111 | c = kzalloc(sizeof(*c), GFP_KERNEL); |
112 | if (!c) { | 112 | if (!c) { |
113 | regmap_debugfs_free_dump_cache(map); | 113 | regmap_debugfs_free_dump_cache(map); |
114 | mutex_unlock(&map->cache_lock); | ||
114 | return base; | 115 | return base; |
115 | } | 116 | } |
116 | c->min = p; | 117 | c->min = p; |
@@ -124,9 +125,7 @@ static unsigned int regmap_debugfs_get_dump_start(struct regmap *map, | |||
124 | /* Close the last entry off if we didn't scan beyond it */ | 125 | /* Close the last entry off if we didn't scan beyond it */ |
125 | if (c) { | 126 | if (c) { |
126 | c->max = p - 1; | 127 | c->max = p - 1; |
127 | fpos_offset = c->max - c->min; | 128 | c->max_reg = i - map->reg_stride; |
128 | reg_offset = fpos_offset / map->debugfs_tot_len; | ||
129 | c->max_reg = c->base_reg + reg_offset; | ||
130 | list_add_tail(&c->list, | 129 | list_add_tail(&c->list, |
131 | &map->debugfs_off_cache); | 130 | &map->debugfs_off_cache); |
132 | } | 131 | } |
@@ -145,12 +144,14 @@ static unsigned int regmap_debugfs_get_dump_start(struct regmap *map, | |||
145 | fpos_offset = from - c->min; | 144 | fpos_offset = from - c->min; |
146 | reg_offset = fpos_offset / map->debugfs_tot_len; | 145 | reg_offset = fpos_offset / map->debugfs_tot_len; |
147 | *pos = c->min + (reg_offset * map->debugfs_tot_len); | 146 | *pos = c->min + (reg_offset * map->debugfs_tot_len); |
147 | mutex_unlock(&map->cache_lock); | ||
148 | return c->base_reg + reg_offset; | 148 | return c->base_reg + reg_offset; |
149 | } | 149 | } |
150 | 150 | ||
151 | *pos = c->max; | 151 | *pos = c->max; |
152 | ret = c->max_reg; | 152 | ret = c->max_reg; |
153 | } | 153 | } |
154 | mutex_unlock(&map->cache_lock); | ||
154 | 155 | ||
155 | return ret; | 156 | return ret; |
156 | } | 157 | } |
@@ -311,6 +312,79 @@ static const struct file_operations regmap_range_fops = { | |||
311 | .llseek = default_llseek, | 312 | .llseek = default_llseek, |
312 | }; | 313 | }; |
313 | 314 | ||
315 | static ssize_t regmap_reg_ranges_read_file(struct file *file, | ||
316 | char __user *user_buf, size_t count, | ||
317 | loff_t *ppos) | ||
318 | { | ||
319 | struct regmap *map = file->private_data; | ||
320 | struct regmap_debugfs_off_cache *c; | ||
321 | loff_t p = 0; | ||
322 | size_t buf_pos = 0; | ||
323 | char *buf; | ||
324 | char *entry; | ||
325 | int ret; | ||
326 | |||
327 | if (*ppos < 0 || !count) | ||
328 | return -EINVAL; | ||
329 | |||
330 | buf = kmalloc(count, GFP_KERNEL); | ||
331 | if (!buf) | ||
332 | return -ENOMEM; | ||
333 | |||
334 | entry = kmalloc(PAGE_SIZE, GFP_KERNEL); | ||
335 | if (!entry) { | ||
336 | kfree(buf); | ||
337 | return -ENOMEM; | ||
338 | } | ||
339 | |||
340 | /* While we are at it, build the register dump cache | ||
341 | * now so the read() operation on the `registers' file | ||
342 | * can benefit from using the cache. We do not care | ||
343 | * about the file position information that is contained | ||
344 | * in the cache, just about the actual register blocks */ | ||
345 | regmap_calc_tot_len(map, buf, count); | ||
346 | regmap_debugfs_get_dump_start(map, 0, *ppos, &p); | ||
347 | |||
348 | /* Reset file pointer as the fixed-format of the `registers' | ||
349 | * file is not compatible with the `range' file */ | ||
350 | p = 0; | ||
351 | mutex_lock(&map->cache_lock); | ||
352 | list_for_each_entry(c, &map->debugfs_off_cache, list) { | ||
353 | snprintf(entry, PAGE_SIZE, "%x-%x", | ||
354 | c->base_reg, c->max_reg); | ||
355 | if (p >= *ppos) { | ||
356 | if (buf_pos + 1 + strlen(entry) > count) | ||
357 | break; | ||
358 | snprintf(buf + buf_pos, count - buf_pos, | ||
359 | "%s", entry); | ||
360 | buf_pos += strlen(entry); | ||
361 | buf[buf_pos] = '\n'; | ||
362 | buf_pos++; | ||
363 | } | ||
364 | p += strlen(entry) + 1; | ||
365 | } | ||
366 | mutex_unlock(&map->cache_lock); | ||
367 | |||
368 | kfree(entry); | ||
369 | ret = buf_pos; | ||
370 | |||
371 | if (copy_to_user(user_buf, buf, buf_pos)) { | ||
372 | ret = -EFAULT; | ||
373 | goto out_buf; | ||
374 | } | ||
375 | |||
376 | *ppos += buf_pos; | ||
377 | out_buf: | ||
378 | kfree(buf); | ||
379 | return ret; | ||
380 | } | ||
381 | |||
382 | static const struct file_operations regmap_reg_ranges_fops = { | ||
383 | .open = simple_open, | ||
384 | .read = regmap_reg_ranges_read_file, | ||
385 | .llseek = default_llseek, | ||
386 | }; | ||
387 | |||
314 | static ssize_t regmap_access_read_file(struct file *file, | 388 | static ssize_t regmap_access_read_file(struct file *file, |
315 | char __user *user_buf, size_t count, | 389 | char __user *user_buf, size_t count, |
316 | loff_t *ppos) | 390 | loff_t *ppos) |
@@ -385,6 +459,7 @@ void regmap_debugfs_init(struct regmap *map, const char *name) | |||
385 | struct regmap_range_node *range_node; | 459 | struct regmap_range_node *range_node; |
386 | 460 | ||
387 | INIT_LIST_HEAD(&map->debugfs_off_cache); | 461 | INIT_LIST_HEAD(&map->debugfs_off_cache); |
462 | mutex_init(&map->cache_lock); | ||
388 | 463 | ||
389 | if (name) { | 464 | if (name) { |
390 | map->debugfs_name = kasprintf(GFP_KERNEL, "%s-%s", | 465 | map->debugfs_name = kasprintf(GFP_KERNEL, "%s-%s", |
@@ -403,6 +478,9 @@ void regmap_debugfs_init(struct regmap *map, const char *name) | |||
403 | debugfs_create_file("name", 0400, map->debugfs, | 478 | debugfs_create_file("name", 0400, map->debugfs, |
404 | map, ®map_name_fops); | 479 | map, ®map_name_fops); |
405 | 480 | ||
481 | debugfs_create_file("range", 0400, map->debugfs, | ||
482 | map, ®map_reg_ranges_fops); | ||
483 | |||
406 | if (map->max_register) { | 484 | if (map->max_register) { |
407 | debugfs_create_file("registers", 0400, map->debugfs, | 485 | debugfs_create_file("registers", 0400, map->debugfs, |
408 | map, ®map_map_fops); | 486 | map, ®map_map_fops); |
@@ -435,7 +513,9 @@ void regmap_debugfs_init(struct regmap *map, const char *name) | |||
435 | void regmap_debugfs_exit(struct regmap *map) | 513 | void regmap_debugfs_exit(struct regmap *map) |
436 | { | 514 | { |
437 | debugfs_remove_recursive(map->debugfs); | 515 | debugfs_remove_recursive(map->debugfs); |
516 | mutex_lock(&map->cache_lock); | ||
438 | regmap_debugfs_free_dump_cache(map); | 517 | regmap_debugfs_free_dump_cache(map); |
518 | mutex_unlock(&map->cache_lock); | ||
439 | kfree(map->debugfs_name); | 519 | kfree(map->debugfs_name); |
440 | } | 520 | } |
441 | 521 | ||
diff --git a/drivers/base/regmap/regmap-irq.c b/drivers/base/regmap/regmap-irq.c index 020ea2b9fd2f..1643e889bafc 100644 --- a/drivers/base/regmap/regmap-irq.c +++ b/drivers/base/regmap/regmap-irq.c | |||
@@ -460,7 +460,8 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags, | |||
460 | ret = request_threaded_irq(irq, NULL, regmap_irq_thread, irq_flags, | 460 | ret = request_threaded_irq(irq, NULL, regmap_irq_thread, irq_flags, |
461 | chip->name, d); | 461 | chip->name, d); |
462 | if (ret != 0) { | 462 | if (ret != 0) { |
463 | dev_err(map->dev, "Failed to request IRQ %d: %d\n", irq, ret); | 463 | dev_err(map->dev, "Failed to request IRQ %d for %s: %d\n", |
464 | irq, chip->name, ret); | ||
464 | goto err_domain; | 465 | goto err_domain; |
465 | } | 466 | } |
466 | 467 | ||
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 58cfb3232428..a941dcfe7590 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c | |||
@@ -228,30 +228,39 @@ static void regmap_format_32_native(void *buf, unsigned int val, | |||
228 | *(u32 *)buf = val << shift; | 228 | *(u32 *)buf = val << shift; |
229 | } | 229 | } |
230 | 230 | ||
231 | static unsigned int regmap_parse_8(void *buf) | 231 | static void regmap_parse_inplace_noop(void *buf) |
232 | { | 232 | { |
233 | u8 *b = buf; | 233 | } |
234 | |||
235 | static unsigned int regmap_parse_8(const void *buf) | ||
236 | { | ||
237 | const u8 *b = buf; | ||
234 | 238 | ||
235 | return b[0]; | 239 | return b[0]; |
236 | } | 240 | } |
237 | 241 | ||
238 | static unsigned int regmap_parse_16_be(void *buf) | 242 | static unsigned int regmap_parse_16_be(const void *buf) |
243 | { | ||
244 | const __be16 *b = buf; | ||
245 | |||
246 | return be16_to_cpu(b[0]); | ||
247 | } | ||
248 | |||
249 | static void regmap_parse_16_be_inplace(void *buf) | ||
239 | { | 250 | { |
240 | __be16 *b = buf; | 251 | __be16 *b = buf; |
241 | 252 | ||
242 | b[0] = be16_to_cpu(b[0]); | 253 | b[0] = be16_to_cpu(b[0]); |
243 | |||
244 | return b[0]; | ||
245 | } | 254 | } |
246 | 255 | ||
247 | static unsigned int regmap_parse_16_native(void *buf) | 256 | static unsigned int regmap_parse_16_native(const void *buf) |
248 | { | 257 | { |
249 | return *(u16 *)buf; | 258 | return *(u16 *)buf; |
250 | } | 259 | } |
251 | 260 | ||
252 | static unsigned int regmap_parse_24(void *buf) | 261 | static unsigned int regmap_parse_24(const void *buf) |
253 | { | 262 | { |
254 | u8 *b = buf; | 263 | const u8 *b = buf; |
255 | unsigned int ret = b[2]; | 264 | unsigned int ret = b[2]; |
256 | ret |= ((unsigned int)b[1]) << 8; | 265 | ret |= ((unsigned int)b[1]) << 8; |
257 | ret |= ((unsigned int)b[0]) << 16; | 266 | ret |= ((unsigned int)b[0]) << 16; |
@@ -259,16 +268,21 @@ static unsigned int regmap_parse_24(void *buf) | |||
259 | return ret; | 268 | return ret; |
260 | } | 269 | } |
261 | 270 | ||
262 | static unsigned int regmap_parse_32_be(void *buf) | 271 | static unsigned int regmap_parse_32_be(const void *buf) |
272 | { | ||
273 | const __be32 *b = buf; | ||
274 | |||
275 | return be32_to_cpu(b[0]); | ||
276 | } | ||
277 | |||
278 | static void regmap_parse_32_be_inplace(void *buf) | ||
263 | { | 279 | { |
264 | __be32 *b = buf; | 280 | __be32 *b = buf; |
265 | 281 | ||
266 | b[0] = be32_to_cpu(b[0]); | 282 | b[0] = be32_to_cpu(b[0]); |
267 | |||
268 | return b[0]; | ||
269 | } | 283 | } |
270 | 284 | ||
271 | static unsigned int regmap_parse_32_native(void *buf) | 285 | static unsigned int regmap_parse_32_native(const void *buf) |
272 | { | 286 | { |
273 | return *(u32 *)buf; | 287 | return *(u32 *)buf; |
274 | } | 288 | } |
@@ -555,16 +569,21 @@ struct regmap *regmap_init(struct device *dev, | |||
555 | goto err_map; | 569 | goto err_map; |
556 | } | 570 | } |
557 | 571 | ||
572 | if (val_endian == REGMAP_ENDIAN_NATIVE) | ||
573 | map->format.parse_inplace = regmap_parse_inplace_noop; | ||
574 | |||
558 | switch (config->val_bits) { | 575 | switch (config->val_bits) { |
559 | case 8: | 576 | case 8: |
560 | map->format.format_val = regmap_format_8; | 577 | map->format.format_val = regmap_format_8; |
561 | map->format.parse_val = regmap_parse_8; | 578 | map->format.parse_val = regmap_parse_8; |
579 | map->format.parse_inplace = regmap_parse_inplace_noop; | ||
562 | break; | 580 | break; |
563 | case 16: | 581 | case 16: |
564 | switch (val_endian) { | 582 | switch (val_endian) { |
565 | case REGMAP_ENDIAN_BIG: | 583 | case REGMAP_ENDIAN_BIG: |
566 | map->format.format_val = regmap_format_16_be; | 584 | map->format.format_val = regmap_format_16_be; |
567 | map->format.parse_val = regmap_parse_16_be; | 585 | map->format.parse_val = regmap_parse_16_be; |
586 | map->format.parse_inplace = regmap_parse_16_be_inplace; | ||
568 | break; | 587 | break; |
569 | case REGMAP_ENDIAN_NATIVE: | 588 | case REGMAP_ENDIAN_NATIVE: |
570 | map->format.format_val = regmap_format_16_native; | 589 | map->format.format_val = regmap_format_16_native; |
@@ -585,6 +604,7 @@ struct regmap *regmap_init(struct device *dev, | |||
585 | case REGMAP_ENDIAN_BIG: | 604 | case REGMAP_ENDIAN_BIG: |
586 | map->format.format_val = regmap_format_32_be; | 605 | map->format.format_val = regmap_format_32_be; |
587 | map->format.parse_val = regmap_parse_32_be; | 606 | map->format.parse_val = regmap_parse_32_be; |
607 | map->format.parse_inplace = regmap_parse_32_be_inplace; | ||
588 | break; | 608 | break; |
589 | case REGMAP_ENDIAN_NATIVE: | 609 | case REGMAP_ENDIAN_NATIVE: |
590 | map->format.format_val = regmap_format_32_native; | 610 | map->format.format_val = regmap_format_32_native; |
@@ -917,8 +937,8 @@ static int _regmap_select_page(struct regmap *map, unsigned int *reg, | |||
917 | return 0; | 937 | return 0; |
918 | } | 938 | } |
919 | 939 | ||
920 | static int _regmap_raw_write(struct regmap *map, unsigned int reg, | 940 | int _regmap_raw_write(struct regmap *map, unsigned int reg, |
921 | const void *val, size_t val_len, bool async) | 941 | const void *val, size_t val_len, bool async) |
922 | { | 942 | { |
923 | struct regmap_range_node *range; | 943 | struct regmap_range_node *range; |
924 | unsigned long flags; | 944 | unsigned long flags; |
@@ -930,7 +950,7 @@ static int _regmap_raw_write(struct regmap *map, unsigned int reg, | |||
930 | size_t len; | 950 | size_t len; |
931 | int i; | 951 | int i; |
932 | 952 | ||
933 | BUG_ON(!map->bus); | 953 | WARN_ON(!map->bus); |
934 | 954 | ||
935 | /* Check for unwritable registers before we start */ | 955 | /* Check for unwritable registers before we start */ |
936 | if (map->writeable_reg) | 956 | if (map->writeable_reg) |
@@ -943,8 +963,7 @@ static int _regmap_raw_write(struct regmap *map, unsigned int reg, | |||
943 | unsigned int ival; | 963 | unsigned int ival; |
944 | int val_bytes = map->format.val_bytes; | 964 | int val_bytes = map->format.val_bytes; |
945 | for (i = 0; i < val_len / val_bytes; i++) { | 965 | for (i = 0; i < val_len / val_bytes; i++) { |
946 | memcpy(map->work_buf, val + (i * val_bytes), val_bytes); | 966 | ival = map->format.parse_val(val + (i * val_bytes)); |
947 | ival = map->format.parse_val(map->work_buf); | ||
948 | ret = regcache_write(map, reg + (i * map->reg_stride), | 967 | ret = regcache_write(map, reg + (i * map->reg_stride), |
949 | ival); | 968 | ival); |
950 | if (ret) { | 969 | if (ret) { |
@@ -999,6 +1018,8 @@ static int _regmap_raw_write(struct regmap *map, unsigned int reg, | |||
999 | if (!async) | 1018 | if (!async) |
1000 | return -ENOMEM; | 1019 | return -ENOMEM; |
1001 | 1020 | ||
1021 | trace_regmap_async_write_start(map->dev, reg, val_len); | ||
1022 | |||
1002 | async->work_buf = kzalloc(map->format.buf_size, | 1023 | async->work_buf = kzalloc(map->format.buf_size, |
1003 | GFP_KERNEL | GFP_DMA); | 1024 | GFP_KERNEL | GFP_DMA); |
1004 | if (!async->work_buf) { | 1025 | if (!async->work_buf) { |
@@ -1079,6 +1100,17 @@ static int _regmap_raw_write(struct regmap *map, unsigned int reg, | |||
1079 | return ret; | 1100 | return ret; |
1080 | } | 1101 | } |
1081 | 1102 | ||
1103 | /** | ||
1104 | * regmap_can_raw_write - Test if regmap_raw_write() is supported | ||
1105 | * | ||
1106 | * @map: Map to check. | ||
1107 | */ | ||
1108 | bool regmap_can_raw_write(struct regmap *map) | ||
1109 | { | ||
1110 | return map->bus && map->format.format_val && map->format.format_reg; | ||
1111 | } | ||
1112 | EXPORT_SYMBOL_GPL(regmap_can_raw_write); | ||
1113 | |||
1082 | static int _regmap_bus_formatted_write(void *context, unsigned int reg, | 1114 | static int _regmap_bus_formatted_write(void *context, unsigned int reg, |
1083 | unsigned int val) | 1115 | unsigned int val) |
1084 | { | 1116 | { |
@@ -1086,7 +1118,7 @@ static int _regmap_bus_formatted_write(void *context, unsigned int reg, | |||
1086 | struct regmap_range_node *range; | 1118 | struct regmap_range_node *range; |
1087 | struct regmap *map = context; | 1119 | struct regmap *map = context; |
1088 | 1120 | ||
1089 | BUG_ON(!map->bus || !map->format.format_write); | 1121 | WARN_ON(!map->bus || !map->format.format_write); |
1090 | 1122 | ||
1091 | range = _regmap_range_lookup(map, reg); | 1123 | range = _regmap_range_lookup(map, reg); |
1092 | if (range) { | 1124 | if (range) { |
@@ -1112,7 +1144,7 @@ static int _regmap_bus_raw_write(void *context, unsigned int reg, | |||
1112 | { | 1144 | { |
1113 | struct regmap *map = context; | 1145 | struct regmap *map = context; |
1114 | 1146 | ||
1115 | BUG_ON(!map->bus || !map->format.format_val); | 1147 | WARN_ON(!map->bus || !map->format.format_val); |
1116 | 1148 | ||
1117 | map->format.format_val(map->work_buf + map->format.reg_bytes | 1149 | map->format.format_val(map->work_buf + map->format.reg_bytes |
1118 | + map->format.pad_bytes, val, 0); | 1150 | + map->format.pad_bytes, val, 0); |
@@ -1202,12 +1234,10 @@ int regmap_raw_write(struct regmap *map, unsigned int reg, | |||
1202 | { | 1234 | { |
1203 | int ret; | 1235 | int ret; |
1204 | 1236 | ||
1205 | if (!map->bus) | 1237 | if (!regmap_can_raw_write(map)) |
1206 | return -EINVAL; | 1238 | return -EINVAL; |
1207 | if (val_len % map->format.val_bytes) | 1239 | if (val_len % map->format.val_bytes) |
1208 | return -EINVAL; | 1240 | return -EINVAL; |
1209 | if (reg % map->reg_stride) | ||
1210 | return -EINVAL; | ||
1211 | 1241 | ||
1212 | map->lock(map->lock_arg); | 1242 | map->lock(map->lock_arg); |
1213 | 1243 | ||
@@ -1242,7 +1272,7 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val, | |||
1242 | 1272 | ||
1243 | if (!map->bus) | 1273 | if (!map->bus) |
1244 | return -EINVAL; | 1274 | return -EINVAL; |
1245 | if (!map->format.parse_val) | 1275 | if (!map->format.parse_inplace) |
1246 | return -EINVAL; | 1276 | return -EINVAL; |
1247 | if (reg % map->reg_stride) | 1277 | if (reg % map->reg_stride) |
1248 | return -EINVAL; | 1278 | return -EINVAL; |
@@ -1260,7 +1290,7 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val, | |||
1260 | goto out; | 1290 | goto out; |
1261 | } | 1291 | } |
1262 | for (i = 0; i < val_count * val_bytes; i += val_bytes) | 1292 | for (i = 0; i < val_count * val_bytes; i += val_bytes) |
1263 | map->format.parse_val(wval + i); | 1293 | map->format.parse_inplace(wval + i); |
1264 | } | 1294 | } |
1265 | /* | 1295 | /* |
1266 | * Some devices does not support bulk write, for | 1296 | * Some devices does not support bulk write, for |
@@ -1338,7 +1368,7 @@ static int _regmap_raw_read(struct regmap *map, unsigned int reg, void *val, | |||
1338 | u8 *u8 = map->work_buf; | 1368 | u8 *u8 = map->work_buf; |
1339 | int ret; | 1369 | int ret; |
1340 | 1370 | ||
1341 | BUG_ON(!map->bus); | 1371 | WARN_ON(!map->bus); |
1342 | 1372 | ||
1343 | range = _regmap_range_lookup(map, reg); | 1373 | range = _regmap_range_lookup(map, reg); |
1344 | if (range) { | 1374 | if (range) { |
@@ -1393,7 +1423,7 @@ static int _regmap_read(struct regmap *map, unsigned int reg, | |||
1393 | int ret; | 1423 | int ret; |
1394 | void *context = _regmap_map_get_context(map); | 1424 | void *context = _regmap_map_get_context(map); |
1395 | 1425 | ||
1396 | BUG_ON(!map->reg_read); | 1426 | WARN_ON(!map->reg_read); |
1397 | 1427 | ||
1398 | if (!map->cache_bypass) { | 1428 | if (!map->cache_bypass) { |
1399 | ret = regcache_read(map, reg, val); | 1429 | ret = regcache_read(map, reg, val); |
@@ -1521,7 +1551,7 @@ int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val, | |||
1521 | 1551 | ||
1522 | if (!map->bus) | 1552 | if (!map->bus) |
1523 | return -EINVAL; | 1553 | return -EINVAL; |
1524 | if (!map->format.parse_val) | 1554 | if (!map->format.parse_inplace) |
1525 | return -EINVAL; | 1555 | return -EINVAL; |
1526 | if (reg % map->reg_stride) | 1556 | if (reg % map->reg_stride) |
1527 | return -EINVAL; | 1557 | return -EINVAL; |
@@ -1548,7 +1578,7 @@ int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val, | |||
1548 | } | 1578 | } |
1549 | 1579 | ||
1550 | for (i = 0; i < val_count * val_bytes; i += val_bytes) | 1580 | for (i = 0; i < val_count * val_bytes; i += val_bytes) |
1551 | map->format.parse_val(val + i); | 1581 | map->format.parse_inplace(val + i); |
1552 | } else { | 1582 | } else { |
1553 | for (i = 0; i < val_count; i++) { | 1583 | for (i = 0; i < val_count; i++) { |
1554 | unsigned int ival; | 1584 | unsigned int ival; |
@@ -1642,6 +1672,8 @@ void regmap_async_complete_cb(struct regmap_async *async, int ret) | |||
1642 | struct regmap *map = async->map; | 1672 | struct regmap *map = async->map; |
1643 | bool wake; | 1673 | bool wake; |
1644 | 1674 | ||
1675 | trace_regmap_async_io_complete(map->dev); | ||
1676 | |||
1645 | spin_lock(&map->async_lock); | 1677 | spin_lock(&map->async_lock); |
1646 | 1678 | ||
1647 | list_del(&async->list); | 1679 | list_del(&async->list); |
@@ -1688,6 +1720,8 @@ int regmap_async_complete(struct regmap *map) | |||
1688 | if (!map->bus->async_write) | 1720 | if (!map->bus->async_write) |
1689 | return 0; | 1721 | return 0; |
1690 | 1722 | ||
1723 | trace_regmap_async_complete_start(map->dev); | ||
1724 | |||
1691 | wait_event(map->async_waitq, regmap_async_is_done(map)); | 1725 | wait_event(map->async_waitq, regmap_async_is_done(map)); |
1692 | 1726 | ||
1693 | spin_lock_irqsave(&map->async_lock, flags); | 1727 | spin_lock_irqsave(&map->async_lock, flags); |
@@ -1695,6 +1729,8 @@ int regmap_async_complete(struct regmap *map) | |||
1695 | map->async_ret = 0; | 1729 | map->async_ret = 0; |
1696 | spin_unlock_irqrestore(&map->async_lock, flags); | 1730 | spin_unlock_irqrestore(&map->async_lock, flags); |
1697 | 1731 | ||
1732 | trace_regmap_async_complete_done(map->dev); | ||
1733 | |||
1698 | return ret; | 1734 | return ret; |
1699 | } | 1735 | } |
1700 | EXPORT_SYMBOL_GPL(regmap_async_complete); | 1736 | EXPORT_SYMBOL_GPL(regmap_async_complete); |
diff --git a/include/linux/regmap.h b/include/linux/regmap.h index bf77dfdabef9..02d84e24b7c2 100644 --- a/include/linux/regmap.h +++ b/include/linux/regmap.h | |||
@@ -389,6 +389,7 @@ int regmap_update_bits_check(struct regmap *map, unsigned int reg, | |||
389 | bool *change); | 389 | bool *change); |
390 | int regmap_get_val_bytes(struct regmap *map); | 390 | int regmap_get_val_bytes(struct regmap *map); |
391 | int regmap_async_complete(struct regmap *map); | 391 | int regmap_async_complete(struct regmap *map); |
392 | bool regmap_can_raw_write(struct regmap *map); | ||
392 | 393 | ||
393 | int regcache_sync(struct regmap *map); | 394 | int regcache_sync(struct regmap *map); |
394 | int regcache_sync_region(struct regmap *map, unsigned int min, | 395 | int regcache_sync_region(struct regmap *map, unsigned int min, |
diff --git a/include/trace/events/regmap.h b/include/trace/events/regmap.h index 41a7dbd570e2..a43a2f67bd8e 100644 --- a/include/trace/events/regmap.h +++ b/include/trace/events/regmap.h | |||
@@ -175,6 +175,54 @@ DEFINE_EVENT(regmap_bool, regmap_cache_bypass, | |||
175 | 175 | ||
176 | ); | 176 | ); |
177 | 177 | ||
178 | DECLARE_EVENT_CLASS(regmap_async, | ||
179 | |||
180 | TP_PROTO(struct device *dev), | ||
181 | |||
182 | TP_ARGS(dev), | ||
183 | |||
184 | TP_STRUCT__entry( | ||
185 | __string( name, dev_name(dev) ) | ||
186 | ), | ||
187 | |||
188 | TP_fast_assign( | ||
189 | __assign_str(name, dev_name(dev)); | ||
190 | ), | ||
191 | |||
192 | TP_printk("%s", __get_str(name)) | ||
193 | ); | ||
194 | |||
195 | DEFINE_EVENT(regmap_block, regmap_async_write_start, | ||
196 | |||
197 | TP_PROTO(struct device *dev, unsigned int reg, int count), | ||
198 | |||
199 | TP_ARGS(dev, reg, count) | ||
200 | ); | ||
201 | |||
202 | DEFINE_EVENT(regmap_async, regmap_async_io_complete, | ||
203 | |||
204 | TP_PROTO(struct device *dev), | ||
205 | |||
206 | TP_ARGS(dev) | ||
207 | |||
208 | ); | ||
209 | |||
210 | DEFINE_EVENT(regmap_async, regmap_async_complete_start, | ||
211 | |||
212 | TP_PROTO(struct device *dev), | ||
213 | |||
214 | TP_ARGS(dev) | ||
215 | |||
216 | ); | ||
217 | |||
218 | DEFINE_EVENT(regmap_async, regmap_async_complete_done, | ||
219 | |||
220 | TP_PROTO(struct device *dev), | ||
221 | |||
222 | TP_ARGS(dev) | ||
223 | |||
224 | ); | ||
225 | |||
178 | #endif /* _TRACE_REGMAP_H */ | 226 | #endif /* _TRACE_REGMAP_H */ |
179 | 227 | ||
180 | /* This part must be outside protection */ | 228 | /* This part must be outside protection */ |