diff options
| -rw-r--r-- | drivers/base/regmap/internal.h | 5 | ||||
| -rw-r--r-- | drivers/base/regmap/regcache.c | 19 | ||||
| -rw-r--r-- | drivers/base/regmap/regmap-spi.c | 3 | ||||
| -rw-r--r-- | drivers/base/regmap/regmap.c | 217 | ||||
| -rw-r--r-- | include/linux/regmap.h | 31 |
5 files changed, 225 insertions, 50 deletions
diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h index 57f777835d97..6873b4ce03f9 100644 --- a/drivers/base/regmap/internal.h +++ b/drivers/base/regmap/internal.h | |||
| @@ -44,7 +44,6 @@ struct regmap_format { | |||
| 44 | 44 | ||
| 45 | struct regmap_async { | 45 | struct regmap_async { |
| 46 | struct list_head list; | 46 | struct list_head list; |
| 47 | struct work_struct cleanup; | ||
| 48 | struct regmap *map; | 47 | struct regmap *map; |
| 49 | void *work_buf; | 48 | void *work_buf; |
| 50 | }; | 49 | }; |
| @@ -64,9 +63,11 @@ struct regmap { | |||
| 64 | void *bus_context; | 63 | void *bus_context; |
| 65 | const char *name; | 64 | const char *name; |
| 66 | 65 | ||
| 66 | bool async; | ||
| 67 | spinlock_t async_lock; | 67 | spinlock_t async_lock; |
| 68 | wait_queue_head_t async_waitq; | 68 | wait_queue_head_t async_waitq; |
| 69 | struct list_head async_list; | 69 | struct list_head async_list; |
| 70 | struct list_head async_free; | ||
| 70 | int async_ret; | 71 | int async_ret; |
| 71 | 72 | ||
| 72 | #ifdef CONFIG_DEBUG_FS | 73 | #ifdef CONFIG_DEBUG_FS |
| @@ -218,7 +219,7 @@ bool regcache_set_val(struct regmap *map, void *base, unsigned int idx, | |||
| 218 | int regcache_lookup_reg(struct regmap *map, unsigned int reg); | 219 | int regcache_lookup_reg(struct regmap *map, unsigned int reg); |
| 219 | 220 | ||
| 220 | int _regmap_raw_write(struct regmap *map, unsigned int reg, | 221 | int _regmap_raw_write(struct regmap *map, unsigned int reg, |
| 221 | const void *val, size_t val_len, bool async); | 222 | const void *val, size_t val_len); |
| 222 | 223 | ||
| 223 | void regmap_async_complete_cb(struct regmap_async *async, int ret); | 224 | void regmap_async_complete_cb(struct regmap_async *async, int ret); |
| 224 | 225 | ||
diff --git a/drivers/base/regmap/regcache.c b/drivers/base/regmap/regcache.c index d6c2d691b6e8..d4dd77134814 100644 --- a/drivers/base/regmap/regcache.c +++ b/drivers/base/regmap/regcache.c | |||
| @@ -307,6 +307,8 @@ int regcache_sync(struct regmap *map) | |||
| 307 | if (!map->cache_dirty) | 307 | if (!map->cache_dirty) |
| 308 | goto out; | 308 | goto out; |
| 309 | 309 | ||
| 310 | map->async = true; | ||
| 311 | |||
| 310 | /* Apply any patch first */ | 312 | /* Apply any patch first */ |
| 311 | map->cache_bypass = 1; | 313 | map->cache_bypass = 1; |
| 312 | for (i = 0; i < map->patch_regs; i++) { | 314 | for (i = 0; i < map->patch_regs; i++) { |
| @@ -332,11 +334,15 @@ int regcache_sync(struct regmap *map) | |||
| 332 | map->cache_dirty = false; | 334 | map->cache_dirty = false; |
| 333 | 335 | ||
| 334 | out: | 336 | out: |
| 335 | trace_regcache_sync(map->dev, name, "stop"); | ||
| 336 | /* Restore the bypass state */ | 337 | /* Restore the bypass state */ |
| 338 | map->async = false; | ||
| 337 | map->cache_bypass = bypass; | 339 | map->cache_bypass = bypass; |
| 338 | map->unlock(map->lock_arg); | 340 | map->unlock(map->lock_arg); |
| 339 | 341 | ||
| 342 | regmap_async_complete(map); | ||
| 343 | |||
| 344 | trace_regcache_sync(map->dev, name, "stop"); | ||
| 345 | |||
| 340 | return ret; | 346 | return ret; |
| 341 | } | 347 | } |
| 342 | EXPORT_SYMBOL_GPL(regcache_sync); | 348 | EXPORT_SYMBOL_GPL(regcache_sync); |
| @@ -375,17 +381,23 @@ int regcache_sync_region(struct regmap *map, unsigned int min, | |||
| 375 | if (!map->cache_dirty) | 381 | if (!map->cache_dirty) |
| 376 | goto out; | 382 | goto out; |
| 377 | 383 | ||
| 384 | map->async = true; | ||
| 385 | |||
| 378 | if (map->cache_ops->sync) | 386 | if (map->cache_ops->sync) |
| 379 | ret = map->cache_ops->sync(map, min, max); | 387 | ret = map->cache_ops->sync(map, min, max); |
| 380 | else | 388 | else |
| 381 | ret = regcache_default_sync(map, min, max); | 389 | ret = regcache_default_sync(map, min, max); |
| 382 | 390 | ||
| 383 | out: | 391 | out: |
| 384 | trace_regcache_sync(map->dev, name, "stop region"); | ||
| 385 | /* Restore the bypass state */ | 392 | /* Restore the bypass state */ |
| 386 | map->cache_bypass = bypass; | 393 | map->cache_bypass = bypass; |
| 394 | map->async = false; | ||
| 387 | map->unlock(map->lock_arg); | 395 | map->unlock(map->lock_arg); |
| 388 | 396 | ||
| 397 | regmap_async_complete(map); | ||
| 398 | |||
| 399 | trace_regcache_sync(map->dev, name, "stop region"); | ||
| 400 | |||
| 389 | return ret; | 401 | return ret; |
| 390 | } | 402 | } |
| 391 | EXPORT_SYMBOL_GPL(regcache_sync_region); | 403 | EXPORT_SYMBOL_GPL(regcache_sync_region); |
| @@ -631,8 +643,7 @@ static int regcache_sync_block_raw_flush(struct regmap *map, const void **data, | |||
| 631 | 643 | ||
| 632 | map->cache_bypass = 1; | 644 | map->cache_bypass = 1; |
| 633 | 645 | ||
| 634 | ret = _regmap_raw_write(map, base, *data, count * val_bytes, | 646 | ret = _regmap_raw_write(map, base, *data, count * val_bytes); |
| 635 | false); | ||
| 636 | 647 | ||
| 637 | map->cache_bypass = 0; | 648 | map->cache_bypass = 0; |
| 638 | 649 | ||
diff --git a/drivers/base/regmap/regmap-spi.c b/drivers/base/regmap/regmap-spi.c index 4c506bd940f3..37f12ae7aada 100644 --- a/drivers/base/regmap/regmap-spi.c +++ b/drivers/base/regmap/regmap-spi.c | |||
| @@ -73,7 +73,8 @@ static int regmap_spi_async_write(void *context, | |||
| 73 | 73 | ||
| 74 | spi_message_init(&async->m); | 74 | spi_message_init(&async->m); |
| 75 | spi_message_add_tail(&async->t[0], &async->m); | 75 | spi_message_add_tail(&async->t[0], &async->m); |
| 76 | spi_message_add_tail(&async->t[1], &async->m); | 76 | if (val) |
| 77 | spi_message_add_tail(&async->t[1], &async->m); | ||
| 77 | 78 | ||
| 78 | async->m.complete = regmap_spi_complete; | 79 | async->m.complete = regmap_spi_complete; |
| 79 | async->m.context = async; | 80 | async->m.context = async; |
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index c1245cae0f43..d0ce2fef43a3 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c | |||
| @@ -42,15 +42,6 @@ static int _regmap_bus_formatted_write(void *context, unsigned int reg, | |||
| 42 | static int _regmap_bus_raw_write(void *context, unsigned int reg, | 42 | static int _regmap_bus_raw_write(void *context, unsigned int reg, |
| 43 | unsigned int val); | 43 | unsigned int val); |
| 44 | 44 | ||
| 45 | static void async_cleanup(struct work_struct *work) | ||
| 46 | { | ||
| 47 | struct regmap_async *async = container_of(work, struct regmap_async, | ||
| 48 | cleanup); | ||
| 49 | |||
| 50 | kfree(async->work_buf); | ||
| 51 | kfree(async); | ||
| 52 | } | ||
| 53 | |||
| 54 | bool regmap_reg_in_ranges(unsigned int reg, | 45 | bool regmap_reg_in_ranges(unsigned int reg, |
| 55 | const struct regmap_range *ranges, | 46 | const struct regmap_range *ranges, |
| 56 | unsigned int nranges) | 47 | unsigned int nranges) |
| @@ -465,6 +456,7 @@ struct regmap *regmap_init(struct device *dev, | |||
| 465 | 456 | ||
| 466 | spin_lock_init(&map->async_lock); | 457 | spin_lock_init(&map->async_lock); |
| 467 | INIT_LIST_HEAD(&map->async_list); | 458 | INIT_LIST_HEAD(&map->async_list); |
| 459 | INIT_LIST_HEAD(&map->async_free); | ||
| 468 | init_waitqueue_head(&map->async_waitq); | 460 | init_waitqueue_head(&map->async_waitq); |
| 469 | 461 | ||
| 470 | if (config->read_flag_mask || config->write_flag_mask) { | 462 | if (config->read_flag_mask || config->write_flag_mask) { |
| @@ -942,12 +934,22 @@ EXPORT_SYMBOL_GPL(regmap_reinit_cache); | |||
| 942 | */ | 934 | */ |
| 943 | void regmap_exit(struct regmap *map) | 935 | void regmap_exit(struct regmap *map) |
| 944 | { | 936 | { |
| 937 | struct regmap_async *async; | ||
| 938 | |||
| 945 | regcache_exit(map); | 939 | regcache_exit(map); |
| 946 | regmap_debugfs_exit(map); | 940 | regmap_debugfs_exit(map); |
| 947 | regmap_range_exit(map); | 941 | regmap_range_exit(map); |
| 948 | if (map->bus && map->bus->free_context) | 942 | if (map->bus && map->bus->free_context) |
| 949 | map->bus->free_context(map->bus_context); | 943 | map->bus->free_context(map->bus_context); |
| 950 | kfree(map->work_buf); | 944 | kfree(map->work_buf); |
| 945 | while (!list_empty(&map->async_free)) { | ||
| 946 | async = list_first_entry_or_null(&map->async_free, | ||
| 947 | struct regmap_async, | ||
| 948 | list); | ||
| 949 | list_del(&async->list); | ||
| 950 | kfree(async->work_buf); | ||
| 951 | kfree(async); | ||
| 952 | } | ||
| 951 | kfree(map); | 953 | kfree(map); |
| 952 | } | 954 | } |
| 953 | EXPORT_SYMBOL_GPL(regmap_exit); | ||
