aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/base/regmap/internal.h5
-rw-r--r--drivers/base/regmap/regcache.c19
-rw-r--r--drivers/base/regmap/regmap-spi.c3
-rw-r--r--drivers/base/regmap/regmap.c217
-rw-r--r--include/linux/regmap.h31
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
45struct regmap_async { 45struct 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,
218int regcache_lookup_reg(struct regmap *map, unsigned int reg); 219int regcache_lookup_reg(struct regmap *map, unsigned int reg);
219 220
220int _regmap_raw_write(struct regmap *map, unsigned int reg, 221int _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
223void regmap_async_complete_cb(struct regmap_async *async, int ret); 224void 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
334out: 336out:
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}
342EXPORT_SYMBOL_GPL(regcache_sync); 348EXPORT_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
383out: 391out:
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}
391EXPORT_SYMBOL_GPL(regcache_sync_region); 403EXPORT_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,
42static int _regmap_bus_raw_write(void *context, unsigned int reg, 42static int _regmap_bus_raw_write(void *context, unsigned int reg,
43 unsigned int val); 43 unsigned int val);
44 44
45static 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
54bool regmap_reg_in_ranges(unsigned int reg, 45bool 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 */
943void regmap_exit(struct regmap *map) 935void 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}
953EXPORT_SYMBOL_GPL(regmap_exit);