diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-11-12 00:47:00 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-11-12 00:47:00 -0500 |
commit | 4fc9ed3344758f22b57db174914b60423c7c1593 (patch) | |
tree | 517e2b3575b319714ea3a8780708c820f8bd20cb /drivers | |
parent | 7e238a2ecd117e16b154e1b0ed77906596600ff5 (diff) | |
parent | 04bc9ac163a2550c7bc32750ea8dd2e049102be2 (diff) |
Merge tag 'regmap-v3.13' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap
Pull regmap updates from Mark Brown:
"The main thing this time around has been some improvments to async
I/O.
- Cleaned up the async I/O support and extended it to allow single
register writes more easily. This is now used where possible for
internally generated I/O, providing performance improvements for
devices that can do async I/O.
- An API for issuing a sequence of register writes as a single
operation. Some devices and buses can take advantage of this to do
the I/O faster.
- Addition of regmap_field APIs which help drivers for devices with
repeated IPs or which move registers around between revisions to
share helpers.
- Support for SPMI buses"
* tag 'regmap-v3.13' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap:
regmap: add SPMI support
regmap: debugfs: Fix a boot time crash with early regmap init
regmap: irq: clear status when disable irq
regmap: Only send a single buffer for async I/O if writing one register
regmap: spi: Handle async writes of only one buffer
regmap: new API regmap_multi_reg_write() definition
regmap: Use async I/O during cache sync
regmap: Use async I/O for patch application
regmap: Fix regmap_bulk_write single-rw mutex deadlock
regmap: Provide asynchronous write and update bits operations
regmap: Simplify the initiation of async I/O
regmap: Don't generate gather writes for single register raw writes
regmap: Cache async work structures
regmap: add helper macro to set min/max range of register
regmap: Add regmap_fields APIs
regmap: add regmap_field_update_bits()
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/base/regmap/Kconfig | 5 | ||||
-rw-r--r-- | drivers/base/regmap/Makefile | 1 | ||||
-rw-r--r-- | drivers/base/regmap/internal.h | 8 | ||||
-rw-r--r-- | drivers/base/regmap/regcache.c | 19 | ||||
-rw-r--r-- | drivers/base/regmap/regmap-debugfs.c | 57 | ||||
-rw-r--r-- | drivers/base/regmap/regmap-irq.c | 16 | ||||
-rw-r--r-- | drivers/base/regmap/regmap-spi.c | 3 | ||||
-rw-r--r-- | drivers/base/regmap/regmap-spmi.c | 90 | ||||
-rw-r--r-- | drivers/base/regmap/regmap.c | 366 |
9 files changed, 507 insertions, 58 deletions
diff --git a/drivers/base/regmap/Kconfig b/drivers/base/regmap/Kconfig index f0d30543fcce..4251570610c9 100644 --- a/drivers/base/regmap/Kconfig +++ b/drivers/base/regmap/Kconfig | |||
@@ -3,7 +3,7 @@ | |||
3 | # subsystems should select the appropriate symbols. | 3 | # subsystems should select the appropriate symbols. |
4 | 4 | ||
5 | config REGMAP | 5 | config REGMAP |
6 | default y if (REGMAP_I2C || REGMAP_SPI || REGMAP_MMIO || REGMAP_IRQ) | 6 | default y if (REGMAP_I2C || REGMAP_SPI || REGMAP_SPMI || REGMAP_MMIO || REGMAP_IRQ) |
7 | select LZO_COMPRESS | 7 | select LZO_COMPRESS |
8 | select LZO_DECOMPRESS | 8 | select LZO_DECOMPRESS |
9 | select IRQ_DOMAIN if REGMAP_IRQ | 9 | select IRQ_DOMAIN if REGMAP_IRQ |
@@ -15,6 +15,9 @@ config REGMAP_I2C | |||
15 | config REGMAP_SPI | 15 | config REGMAP_SPI |
16 | tristate | 16 | tristate |
17 | 17 | ||
18 | config REGMAP_SPMI | ||
19 | tristate | ||
20 | |||
18 | config REGMAP_MMIO | 21 | config REGMAP_MMIO |
19 | tristate | 22 | tristate |
20 | 23 | ||
diff --git a/drivers/base/regmap/Makefile b/drivers/base/regmap/Makefile index cf129980abd0..a7c670b4123a 100644 --- a/drivers/base/regmap/Makefile +++ b/drivers/base/regmap/Makefile | |||
@@ -3,5 +3,6 @@ obj-$(CONFIG_REGMAP) += regcache-rbtree.o regcache-lzo.o regcache-flat.o | |||
3 | obj-$(CONFIG_DEBUG_FS) += regmap-debugfs.o | 3 | obj-$(CONFIG_DEBUG_FS) += regmap-debugfs.o |
4 | obj-$(CONFIG_REGMAP_I2C) += regmap-i2c.o | 4 | obj-$(CONFIG_REGMAP_I2C) += regmap-i2c.o |
5 | obj-$(CONFIG_REGMAP_SPI) += regmap-spi.o | 5 | obj-$(CONFIG_REGMAP_SPI) += regmap-spi.o |
6 | obj-$(CONFIG_REGMAP_SPMI) += regmap-spmi.o | ||
6 | obj-$(CONFIG_REGMAP_MMIO) += regmap-mmio.o | 7 | obj-$(CONFIG_REGMAP_MMIO) += regmap-mmio.o |
7 | obj-$(CONFIG_REGMAP_IRQ) += regmap-irq.o | 8 | obj-$(CONFIG_REGMAP_IRQ) += regmap-irq.o |
diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h index 57f777835d97..33414b1de201 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 |
@@ -179,6 +180,9 @@ struct regmap_field { | |||
179 | /* lsb */ | 180 | /* lsb */ |
180 | unsigned int shift; | 181 | unsigned int shift; |
181 | unsigned int reg; | 182 | unsigned int reg; |
183 | |||
184 | unsigned int id_size; | ||
185 | unsigned int id_offset; | ||
182 | }; | 186 | }; |
183 | 187 | ||
184 | #ifdef CONFIG_DEBUG_FS | 188 | #ifdef CONFIG_DEBUG_FS |
@@ -218,7 +222,7 @@ bool regcache_set_val(struct regmap *map, void *base, unsigned int idx, | |||
218 | int regcache_lookup_reg(struct regmap *map, unsigned int reg); | 222 | int regcache_lookup_reg(struct regmap *map, unsigned int reg); |
219 | 223 | ||
220 | int _regmap_raw_write(struct regmap *map, unsigned int reg, | 224 | int _regmap_raw_write(struct regmap *map, unsigned int reg, |
221 | const void *val, size_t val_len, bool async); | 225 | const void *val, size_t val_len); |
222 | 226 | ||
223 | void regmap_async_complete_cb(struct regmap_async *async, int ret); | 227 | void regmap_async_complete_cb(struct regmap_async *async, int ret); |
224 | 228 | ||
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-debugfs.c b/drivers/base/regmap/regmap-debugfs.c index de11ecaf3833..c5471cd6ebb7 100644 --- a/drivers/base/regmap/regmap-debugfs.c +++ b/drivers/base/regmap/regmap-debugfs.c | |||
@@ -15,10 +15,19 @@ | |||
15 | #include <linux/debugfs.h> | 15 | #include <linux/debugfs.h> |
16 | #include <linux/uaccess.h> | 16 | #include <linux/uaccess.h> |
17 | #include <linux/device.h> | 17 | #include <linux/device.h> |
18 | #include <linux/list.h> | ||
18 | 19 | ||
19 | #include "internal.h" | 20 | #include "internal.h" |
20 | 21 | ||
22 | struct regmap_debugfs_node { | ||
23 | struct regmap *map; | ||
24 | const char *name; | ||
25 | struct list_head link; | ||
26 | }; | ||
27 | |||
21 | static struct dentry *regmap_debugfs_root; | 28 | static struct dentry *regmap_debugfs_root; |
29 | static LIST_HEAD(regmap_debugfs_early_list); | ||
30 | static DEFINE_MUTEX(regmap_debugfs_early_lock); | ||
22 | 31 | ||
23 | /* Calculate the length of a fixed format */ | 32 | /* Calculate the length of a fixed format */ |
24 | static size_t regmap_calc_reg_len(int max_val, char *buf, size_t buf_size) | 33 | static size_t regmap_calc_reg_len(int max_val, char *buf, size_t buf_size) |
@@ -465,6 +474,20 @@ void regmap_debugfs_init(struct regmap *map, const char *name) | |||
465 | struct rb_node *next; | 474 | struct rb_node *next; |
466 | struct regmap_range_node *range_node; | 475 | struct regmap_range_node *range_node; |
467 | 476 | ||
477 | /* If we don't have the debugfs root yet, postpone init */ | ||
478 | if (!regmap_debugfs_root) { | ||
479 | struct regmap_debugfs_node *node; | ||
480 | node = kzalloc(sizeof(*node), GFP_KERNEL); | ||
481 | if (!node) | ||
482 | return; | ||
483 | node->map = map; | ||
484 | node->name = name; | ||
485 | mutex_lock(®map_debugfs_early_lock); | ||
486 | list_add(&node->link, ®map_debugfs_early_list); | ||
487 | mutex_unlock(®map_debugfs_early_lock); | ||
488 | return; | ||
489 | } | ||
490 | |||
468 | INIT_LIST_HEAD(&map->debugfs_off_cache); | 491 | INIT_LIST_HEAD(&map->debugfs_off_cache); |
469 | mutex_init(&map->cache_lock); | 492 | mutex_init(&map->cache_lock); |
470 | 493 | ||
@@ -519,18 +542,42 @@ void regmap_debugfs_init(struct regmap *map, const char *name) | |||
519 | 542 | ||
520 | void regmap_debugfs_exit(struct regmap *map) | 543 | void regmap_debugfs_exit(struct regmap *map) |
521 | { | 544 | { |
522 | debugfs_remove_recursive(map->debugfs); | 545 | if (map->debugfs) { |
523 | mutex_lock(&map->cache_lock); | 546 | debugfs_remove_recursive(map->debugfs); |
524 | regmap_debugfs_free_dump_cache(map); | 547 | mutex_lock(&map->cache_lock); |
525 | mutex_unlock(&map->cache_lock); | 548 | regmap_debugfs_free_dump_cache(map); |
526 | kfree(map->debugfs_name); | 549 | mutex_unlock(&map->cache_lock); |
550 | kfree(map->debugfs_name); | ||
551 | } else { | ||
552 | struct regmap_debugfs_node *node, *tmp; | ||
553 | |||
554 | mutex_lock(®map_debugfs_early_lock); | ||
555 | list_for_each_entry_safe(node, tmp, ®map_debugfs_early_list, | ||
556 | link) { | ||
557 | if (node->map == map) { | ||
558 | list_del(&node->link); | ||
559 | kfree(node); | ||
560 | } | ||
561 | } | ||
562 | mutex_unlock(®map_debugfs_early_lock); | ||
563 | } | ||
527 | } | 564 | } |
528 | 565 | ||
529 | void regmap_debugfs_initcall(void) | 566 | void regmap_debugfs_initcall(void) |
530 | { | 567 | { |
568 | struct regmap_debugfs_node *node, *tmp; | ||
569 | |||
531 | regmap_debugfs_root = debugfs_create_dir("regmap", NULL); | 570 | regmap_debugfs_root = debugfs_create_dir("regmap", NULL); |
532 | if (!regmap_debugfs_root) { | 571 | if (!regmap_debugfs_root) { |
533 | pr_warn("regmap: Failed to create debugfs root\n"); | 572 | pr_warn("regmap: Failed to create debugfs root\n"); |
534 | return; | 573 | return; |
535 | } | 574 | } |
575 | |||
576 | mutex_lock(®map_debugfs_early_lock); | ||
577 | list_for_each_entry_safe(node, tmp, ®map_debugfs_early_list, link) { | ||
578 | regmap_debugfs_init(node->map, node->name); | ||
579 | list_del(&node->link); | ||
580 | kfree(node); | ||
581 | } | ||
582 | mutex_unlock(®map_debugfs_early_lock); | ||
536 | } | 583 | } |
diff --git a/drivers/base/regmap/regmap-irq.c b/drivers/base/regmap/regmap-irq.c index d10456ffd811..763c60d3d277 100644 --- a/drivers/base/regmap/regmap-irq.c +++ b/drivers/base/regmap/regmap-irq.c | |||
@@ -105,6 +105,22 @@ static void regmap_irq_sync_unlock(struct irq_data *data) | |||
105 | "Failed to sync wakes in %x: %d\n", | 105 | "Failed to sync wakes in %x: %d\n", |
106 | reg, ret); | 106 | reg, ret); |
107 | } | 107 | } |
108 | |||
109 | if (!d->chip->init_ack_masked) | ||
110 | continue; | ||
111 | /* | ||
112 | * Ack all the masked interrupts uncondictionly, | ||
113 | * OR if there is masked interrupt which hasn't been Acked, | ||
114 | * it'll be ignored in irq handler, then may introduce irq storm | ||
115 | */ | ||
116 | if (d->mask_buf[i] && d->chip->ack_base) { | ||
117 | reg = d->chip->ack_base + | ||
118 | (i * map->reg_stride * d->irq_reg_stride); | ||
119 | ret = regmap_write(map, reg, d->mask_buf[i]); | ||
120 | if (ret != 0) | ||
121 | dev_err(d->map->dev, "Failed to ack 0x%x: %d\n", | ||
122 | reg, ret); | ||
123 | } | ||
108 | } | 124 | } |
109 | 125 | ||
110 | if (d->chip->runtime_pm) | 126 | if (d->chip->runtime_pm) |
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-spmi.c b/drivers/base/regmap/regmap-spmi.c new file mode 100644 index 000000000000..ac2391013db1 --- /dev/null +++ b/drivers/base/regmap/regmap-spmi.c | |||
@@ -0,0 +1,90 @@ | |||
1 | /* | ||
2 | * Register map access API - SPMI support | ||
3 | * | ||
4 | * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. | ||
5 | * | ||
6 | * Based on regmap-i2c.c: | ||
7 | * Copyright 2011 Wolfson Microelectronics plc | ||
8 | * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License version 2 and | ||
12 | * only version 2 as published by the Free Software Foundation. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | */ | ||
20 | #include <linux/regmap.h> | ||
21 | #include <linux/spmi.h> | ||
22 | #include <linux/module.h> | ||
23 | #include <linux/init.h> | ||
24 | |||
25 | static int regmap_spmi_read(void *context, | ||
26 | const void *reg, size_t reg_size, | ||
27 | void *val, size_t val_size) | ||
28 | { | ||
29 | BUG_ON(reg_size != 2); | ||
30 | return spmi_ext_register_readl(context, *(u16 *)reg, | ||
31 | val, val_size); | ||
32 | } | ||
33 | |||
34 | static int regmap_spmi_gather_write(void *context, | ||
35 | const void *reg, size_t reg_size, | ||
36 | const void *val, size_t val_size) | ||
37 | { | ||
38 | BUG_ON(reg_size != 2); | ||
39 | return spmi_ext_register_writel(context, *(u16 *)reg, val, val_size); | ||
40 | } | ||
41 | |||
42 | static int regmap_spmi_write(void *context, const void *data, | ||
43 | size_t count) | ||
44 | { | ||
45 | BUG_ON(count < 2); | ||
46 | return regmap_spmi_gather_write(context, data, 2, data + 2, count - 2); | ||
47 | } | ||
48 | |||
49 | static struct regmap_bus regmap_spmi = { | ||
50 | .read = regmap_spmi_read, | ||
51 | .write = regmap_spmi_write, | ||
52 | .gather_write = regmap_spmi_gather_write, | ||
53 | .reg_format_endian_default = REGMAP_ENDIAN_NATIVE, | ||
54 | .val_format_endian_default = REGMAP_ENDIAN_NATIVE, | ||
55 | }; | ||
56 | |||
57 | /** | ||
58 | * regmap_init_spmi(): Initialize register map | ||
59 | * | ||
60 | * @sdev: Device that will be interacted with | ||
61 | * @config: Configuration for register map | ||
62 | * | ||
63 | * The return value will be an ERR_PTR() on error or a valid pointer to | ||
64 | * a struct regmap. | ||
65 | */ | ||
66 | struct regmap *regmap_init_spmi(struct spmi_device *sdev, | ||
67 | const struct regmap_config *config) | ||
68 | { | ||
69 | return regmap_init(&sdev->dev, ®map_spmi, sdev, config); | ||
70 | } | ||
71 | EXPORT_SYMBOL_GPL(regmap_init_spmi); | ||
72 | |||
73 | /** | ||
74 | * devm_regmap_init_spmi(): Initialise managed register map | ||
75 | * | ||
76 | * @sdev: Device that will be interacted with | ||
77 | * @config: Configuration for register map | ||
78 | * | ||
79 | * The return value will be an ERR_PTR() on error or a valid pointer | ||
80 | * to a struct regmap. The regmap will be automatically freed by the | ||
81 | * device management code. | ||
82 | */ | ||
83 | struct regmap *devm_regmap_init_spmi(struct spmi_device *sdev, | ||
84 | const struct regmap_config *config) | ||
85 | { | ||
86 | return devm_regmap_init(&sdev->dev, ®map_spmi, sdev, config); | ||
87 | } | ||
88 | EXPORT_SYMBOL_GPL(devm_regmap_init_spmi); | ||
89 | |||
90 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 7d689a15c500..9c021d9cace0 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) { |
@@ -821,6 +813,8 @@ static void regmap_field_init(struct regmap_field *rm_field, | |||
821 | rm_field->reg = reg_field.reg; | 813 | rm_field->reg = reg_field.reg; |
822 | rm_field->shift = reg_field.lsb; | 814 | rm_field->shift = reg_field.lsb; |
823 | rm_field->mask = ((BIT(field_bits) - 1) << reg_field.lsb); | 815 | rm_field->mask = ((BIT(field_bits) - 1) << reg_field.lsb); |
816 | rm_field->id_size = reg_field.id_size; | ||
817 | rm_field->id_offset = reg_field.id_offset; | ||
824 | } | 818 | } |
825 | 819 | ||
826 | /** | 820 | /** |
@@ -942,12 +936,22 @@ EXPORT_SYMBOL_GPL(regmap_reinit_cache); | |||
942 | */ | 936 | */ |
943 | void regmap_exit(struct regmap *map) | 937 | void regmap_exit(struct regmap *map) |
944 | { | 938 | { |
939 | struct regmap_async *async; | ||
940 | |||
945 | regcache_exit(map); | 941 | regcache_exit(map); |
946 | regmap_debugfs_exit(map); | 942 | regmap_debugfs_exit(map); |
947 | regmap_range_exit(map); | 943 | regmap_range_exit(map); |
948 | if (map->bus && map->bus->free_context) | 944 | if (map->bus && map->bus->free_context) |
949 | map->bus->free_context(map->bus_context); | 945 | map->bus->free_context(map->bus_context); |
950 | kfree(map->work_buf); | 946 | kfree(map->work_buf); |
947 | while (!list_empty(&map->async_free)) { | ||
948 | async = list_first_entry_or_null(&map->async_free, | ||
949 | struct regmap_async, | ||
950 | list); | ||
951 | list_del(&async->list); | ||
952 | kfree(async->work_buf); | ||
953 | kfree(async); | ||
954 | } | ||
951 | kfree(map); | 955 | kfree(map); |
952 | } | 956 | } |
953 | EXPORT_SYMBOL_GPL(regmap_exit); | 957 | EXPORT_SYMBOL_GPL(regmap_exit); |
@@ -1039,7 +1043,7 @@ static int _regmap_select_page(struct regmap *map, unsigned int *reg, | |||
1039 | } | 1043 | } |
1040 | 1044 | ||
1041 | int _regmap_raw_write(struct regmap *map, unsigned int reg, | 1045 | int _regmap_raw_write(struct regmap *map, unsigned int reg, |
1042 | const void *val, size_t val_len, bool async) | 1046 | const void *val, size_t val_len) |
1043 | { | 1047 | { |
1044 | struct regmap_range_node *range; | 1048 | struct regmap_range_node *range; |
1045 | unsigned long flags; | 1049 | unsigned long flags; |
@@ -1091,7 +1095,7 @@ int _regmap_raw_write(struct regmap *map, unsigned int reg, | |||
1091 | dev_dbg(map->dev, "Writing window %d/%zu\n", | 1095 | dev_dbg(map->dev, "Writing window %d/%zu\n", |
1092 | win_residue, val_len / map->format.val_bytes); | 1096 | win_residue, val_len / map->format.val_bytes); |
1093 | ret = _regmap_raw_write(map, reg, val, win_residue * | 1097 | ret = _regmap_raw_write(map, reg, val, win_residue * |
1094 | map->format.val_bytes, async); | 1098 | map->format.val_bytes); |
1095 | if (ret != 0) | 1099 | if (ret != 0) |
1096 | return ret; | 1100 | return ret; |
1097 | 1101 | ||
@@ -1114,49 +1118,72 @@ int _regmap_raw_write(struct regmap *map, unsigned int reg, | |||
1114 | 1118 | ||
1115 | u8[0] |= map->write_flag_mask; | 1119 | u8[0] |= map->write_flag_mask; |
1116 | 1120 | ||
1117 | if (async && map->bus->async_write) { | 1121 | /* |
1118 | struct regmap_async *async = map->bus->async_alloc(); | 1122 | * Essentially all I/O mechanisms will be faster with a single |
1119 | if (!async) | 1123 | * buffer to write. Since register syncs often generate raw |
1120 | return -ENOMEM; | 1124 | * writes of single registers optimise that case. |
1125 | */ | ||
1126 | if (val != work_val && val_len == map->format.val_bytes) { | ||
1127 | memcpy(work_val, val, map->format.val_bytes); | ||
1128 | val = work_val; | ||
1129 | } | ||
1130 | |||
1131 | if (map->async && map->bus->async_write) { | ||
1132 | struct regmap_async *async; | ||
1121 | 1133 | ||
1122 | trace_regmap_async_write_start(map->dev, reg, val_len); | 1134 | trace_regmap_async_write_start(map->dev, reg, val_len); |
1123 | 1135 | ||
1124 | async->work_buf = kzalloc(map->format.buf_size, | 1136 | spin_lock_irqsave(&map->async_lock, flags); |
1125 | GFP_KERNEL | GFP_DMA); | 1137 | async = list_first_entry_or_null(&map->async_free, |
1126 | if (!async->work_buf) { | 1138 | struct regmap_async, |
1127 | kfree(async); | 1139 | list); |
1128 | return -ENOMEM; | 1140 | if (async) |
1141 | list_del(&async->list); | ||
1142 | spin_unlock_irqrestore(&map->async_lock, flags); | ||
1143 | |||
1144 | if (!async) { | ||
1145 | async = map->bus->async_alloc(); | ||
1146 | if (!async) | ||
1147 | return -ENOMEM; | ||
1148 | |||
1149 | async->work_buf = kzalloc(map->format.buf_size, | ||
1150 | GFP_KERNEL | GFP_DMA); | ||
1151 | if (!async->work_buf) { | ||
1152 | kfree(async); | ||
1153 | return -ENOMEM; | ||
1154 | } | ||
1129 | } | 1155 | } |
1130 | 1156 | ||
1131 | INIT_WORK(&async->cleanup, async_cleanup); | ||
1132 | async->map = map; | 1157 | async->map = map; |
1133 | 1158 | ||
1134 | /* If the caller supplied the value we can use it safely. */ | 1159 | /* If the caller supplied the value we can use it safely. */ |
1135 | memcpy(async->work_buf, map->work_buf, map->format.pad_bytes + | 1160 | memcpy(async->work_buf, map->work_buf, map->format.pad_bytes + |
1136 | map->format.reg_bytes + map->format.val_bytes); | 1161 | map->format.reg_bytes + map->format.val_bytes); |
1137 | if (val == work_val) | ||
1138 | val = async->work_buf + map->format.pad_bytes + | ||
1139 | map->format.reg_bytes; | ||
1140 | 1162 | ||
1141 | spin_lock_irqsave(&map->async_lock, flags); | 1163 | spin_lock_irqsave(&map->async_lock, flags); |
1142 | list_add_tail(&async->list, &map->async_list); | 1164 | list_add_tail(&async->list, &map->async_list); |
1143 | spin_unlock_irqrestore(&map->async_lock, flags); | 1165 | spin_unlock_irqrestore(&map->async_lock, flags); |
1144 | 1166 | ||
1145 | ret = map->bus->async_write(map->bus_context, async->work_buf, | 1167 | if (val != work_val) |
1146 | map->format.reg_bytes + | 1168 | ret = map->bus->async_write(map->bus_context, |
1147 | map->format.pad_bytes, | 1169 | async->work_buf, |
1148 | val, val_len, async); | 1170 | map->format.reg_bytes + |
1171 | map->format.pad_bytes, | ||
1172 | val, val_len, async); | ||
1173 | else | ||
1174 | ret = map->bus->async_write(map->bus_context, | ||
1175 | async->work_buf, | ||
1176 | map->format.reg_bytes + | ||
1177 | map->format.pad_bytes + | ||
1178 | val_len, NULL, 0, async); | ||
1149 | 1179 | ||
1150 | if (ret != 0) { | 1180 | if (ret != 0) { |
1151 | dev_err(map->dev, "Failed to schedule write: %d\n", | 1181 | dev_err(map->dev, "Failed to schedule write: %d\n", |
1152 | ret); | 1182 | ret); |
1153 | 1183 | ||
1154 | spin_lock_irqsave(&map->async_lock, flags); | 1184 | spin_lock_irqsave(&map->async_lock, flags); |
1155 | list_del(&async->list); | 1185 | list_move(&async->list, &map->async_free); |
1156 | spin_unlock_irqrestore(&map->async_lock, flags); | 1186 | spin_unlock_irqrestore(&map->async_lock, flags); |
1157 | |||
1158 | kfree(async->work_buf); | ||
1159 | kfree(async); | ||
1160 | } | 1187 | } |
1161 | 1188 | ||
1162 | return ret; | 1189 | return ret; |
@@ -1253,7 +1280,7 @@ static int _regmap_bus_raw_write(void *context, unsigned int reg, | |||
1253 | map->work_buf + | 1280 | map->work_buf + |
1254 | map->format.reg_bytes + | 1281 | map->format.reg_bytes + |
1255 | map->format.pad_bytes, | 1282 | map->format.pad_bytes, |
1256 | map->format.val_bytes, false); | 1283 | map->format.val_bytes); |
1257 | } | 1284 | } |
1258 | 1285 | ||
1259 | static inline void *_regmap_map_get_context(struct regmap *map) | 1286 | static inline void *_regmap_map_get_context(struct regmap *map) |
@@ -1318,6 +1345,37 @@ int regmap_write(struct regmap *map, unsigned int reg, unsigned int val) | |||
1318 | EXPORT_SYMBOL_GPL(regmap_write); | 1345 | EXPORT_SYMBOL_GPL(regmap_write); |
1319 | 1346 | ||
1320 | /** | 1347 | /** |
1348 | * regmap_write_async(): Write a value to a single register asynchronously | ||
1349 | * | ||
1350 | * @map: Register map to write to | ||
1351 | * @reg: Register to write to | ||
1352 | * @val: Value to be written | ||
1353 | * | ||
1354 | * A value of zero will be returned on success, a negative errno will | ||
1355 | * be returned in error cases. | ||
1356 | */ | ||
1357 | int regmap_write_async(struct regmap *map, unsigned int reg, unsigned int val) | ||
1358 | { | ||
1359 | int ret; | ||
1360 | |||
1361 | if (reg % map->reg_stride) | ||
1362 | return -EINVAL; | ||
1363 | |||
1364 | map->lock(map->lock_arg); | ||
1365 | |||
1366 | map->async = true; | ||
1367 | |||
1368 | ret = _regmap_write(map, reg, val); | ||
1369 | |||
1370 | map->async = false; | ||
1371 | |||
1372 | map->unlock(map->lock_arg); | ||
1373 | |||
1374 | return ret; | ||
1375 | } | ||
1376 | EXPORT_SYMBOL_GPL(regmap_write_async); | ||
1377 | |||
1378 | /** | ||
1321 | * regmap_raw_write(): Write raw values to one or more registers | 1379 | * regmap_raw_write(): Write raw values to one or more registers |
1322 | * | 1380 | * |
1323 | * @map: Register map to write to | 1381 | * @map: Register map to write to |
@@ -1345,7 +1403,7 @@ int regmap_raw_write(struct regmap *map, unsigned int reg, | |||
1345 | 1403 | ||
1346 | map->lock(map->lock_arg); | 1404 | map->lock(map->lock_arg); |
1347 | 1405 | ||
1348 | ret = _regmap_raw_write(map, reg, val, val_len, false); | 1406 | ret = _regmap_raw_write(map, reg, val, val_len); |
1349 | 1407 | ||
1350 | map->unlock(map->lock_arg); | 1408 | map->unlock(map->lock_arg); |
1351 | 1409 | ||
@@ -1369,6 +1427,74 @@ int regmap_field_write(struct regmap_field *field, unsigned int val) | |||
1369 | } | 1427 | } |
1370 | EXPORT_SYMBOL_GPL(regmap_field_write); | 1428 | EXPORT_SYMBOL_GPL(regmap_field_write); |
1371 | 1429 | ||
1430 | /** | ||
1431 | * regmap_field_update_bits(): Perform a read/modify/write cycle | ||
1432 | * on the register field | ||
1433 | * | ||
1434 | * @field: Register field to write to | ||
1435 | * @mask: Bitmask to change | ||
1436 | * @val: Value to be written | ||
1437 | * | ||
1438 | * A value of zero will be returned on success, a negative errno will | ||
1439 | * be returned in error cases. | ||
1440 | */ | ||
1441 | int regmap_field_update_bits(struct regmap_field *field, unsigned int mask, unsigned int val) | ||
1442 | { | ||
1443 | mask = (mask << field->shift) & field->mask; | ||
1444 | |||
1445 | return regmap_update_bits(field->regmap, field->reg, | ||
1446 | mask, val << field->shift); | ||
1447 | } | ||
1448 | EXPORT_SYMBOL_GPL(regmap_field_update_bits); | ||
1449 | |||
1450 | /** | ||
1451 | * regmap_fields_write(): Write a value to a single register field with port ID | ||
1452 | * | ||
1453 | * @field: Register field to write to | ||
1454 | * @id: port ID | ||
1455 | * @val: Value to be written | ||
1456 | * | ||
1457 | * A value of zero will be returned on success, a negative errno will | ||
1458 | * be returned in error cases. | ||
1459 | */ | ||
1460 | int regmap_fields_write(struct regmap_field *field, unsigned int id, | ||
1461 | unsigned int val) | ||
1462 | { | ||
1463 | if (id >= field->id_size) | ||
1464 | return -EINVAL; | ||
1465 | |||
1466 | return regmap_update_bits(field->regmap, | ||
1467 | field->reg + (field->id_offset * id), | ||
1468 | field->mask, val << field->shift); | ||
1469 | } | ||
1470 | EXPORT_SYMBOL_GPL(regmap_fields_write); | ||
1471 | |||
1472 | /** | ||
1473 | * regmap_fields_update_bits(): Perform a read/modify/write cycle | ||
1474 | * on the register field | ||
1475 | * | ||
1476 | * @field: Register field to write to | ||
1477 | * @id: port ID | ||
1478 | * @mask: Bitmask to change | ||
1479 | * @val: Value to be written | ||
1480 | * | ||
1481 | * A value of zero will be returned on success, a negative errno will | ||
1482 | * be returned in error cases. | ||
1483 | */ | ||
1484 | int regmap_fields_update_bits(struct regmap_field *field, unsigned int id, | ||
1485 | unsigned int mask, unsigned int val) | ||
1486 | { | ||
1487 | if (id >= field->id_size) | ||
1488 | return -EINVAL; | ||
1489 | |||
1490 | mask = (mask << field->shift) & field->mask; | ||
1491 | |||
1492 | return regmap_update_bits(field->regmap, | ||
1493 | field->reg + (field->id_offset * id), | ||
1494 | mask, val << field->shift); | ||
1495 | } | ||
1496 | EXPORT_SYMBOL_GPL(regmap_fields_update_bits); | ||
1497 | |||
1372 | /* | 1498 | /* |
1373 | * regmap_bulk_write(): Write multiple registers to the device | 1499 | * regmap_bulk_write(): Write multiple registers to the device |
1374 | * | 1500 | * |
@@ -1418,16 +1544,15 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val, | |||
1418 | */ | 1544 | */ |
1419 | if (map->use_single_rw) { | 1545 | if (map->use_single_rw) { |
1420 | for (i = 0; i < val_count; i++) { | 1546 | for (i = 0; i < val_count; i++) { |
1421 | ret = regmap_raw_write(map, | 1547 | ret = _regmap_raw_write(map, |
1422 | reg + (i * map->reg_stride), | 1548 | reg + (i * map->reg_stride), |
1423 | val + (i * val_bytes), | 1549 | val + (i * val_bytes), |
1424 | val_bytes); | 1550 | val_bytes); |
1425 | if (ret != 0) | 1551 | if (ret != 0) |
1426 | return ret; | 1552 | return ret; |
1427 | } | 1553 | } |
1428 | } else { | 1554 | } else { |
1429 | ret = _regmap_raw_write(map, reg, wval, val_bytes * val_count, | 1555 | ret = _regmap_raw_write(map, reg, wval, val_bytes * val_count); |
1430 | false); | ||
1431 | } | 1556 | } |
1432 | 1557 | ||
1433 | if (val_bytes != 1) | 1558 | if (val_bytes != 1) |
@@ -1439,6 +1564,47 @@ out: | |||
1439 | } | 1564 | } |
1440 | EXPORT_SYMBOL_GPL(regmap_bulk_write); | 1565 | EXPORT_SYMBOL_GPL(regmap_bulk_write); |
1441 | 1566 | ||
1567 | /* | ||
1568 | * regmap_multi_reg_write(): Write multiple registers to the device | ||
1569 | * | ||
1570 | * where the set of register are supplied in any order | ||
1571 | * | ||
1572 | * @map: Register map to write to | ||
1573 | * @regs: Array of structures containing register,value to be written | ||
1574 | * @num_regs: Number of registers to write | ||
1575 | * | ||
1576 | * This function is intended to be used for writing a large block of data | ||
1577 | * atomically to the device in single transfer for those I2C client devices | ||
1578 | * that implement this alternative block write mode. | ||
1579 | * | ||
1580 | * A value of zero will be returned on success, a negative errno will | ||
1581 | * be returned in error cases. | ||
1582 | */ | ||
1583 | int regmap_multi_reg_write(struct regmap *map, struct reg_default *regs, | ||
1584 | int num_regs) | ||
1585 | { | ||
1586 | int ret = 0, i; | ||
1587 | |||
1588 | for (i = 0; i < num_regs; i++) { | ||
1589 | int reg = regs[i].reg; | ||
1590 | if (reg % map->reg_stride) | ||
1591 | return -EINVAL; | ||
1592 | } | ||
1593 | |||
1594 | map->lock(map->lock_arg); | ||
1595 | |||
1596 | for (i = 0; i < num_regs; i++) { | ||
1597 | ret = _regmap_write(map, regs[i].reg, regs[i].def); | ||
1598 | if (ret != 0) | ||
1599 | goto out; | ||
1600 | } | ||
1601 | out: | ||
1602 | map->unlock(map->lock_arg); | ||
1603 | |||
1604 | return ret; | ||
1605 | } | ||
1606 | EXPORT_SYMBOL_GPL(regmap_multi_reg_write); | ||
1607 | |||
1442 | /** | 1608 | /** |
1443 | * regmap_raw_write_async(): Write raw values to one or more registers | 1609 | * regmap_raw_write_async(): Write raw values to one or more registers |
1444 | * asynchronously | 1610 | * asynchronously |
@@ -1473,7 +1639,11 @@ int regmap_raw_write_async(struct regmap *map, unsigned int reg, | |||
1473 | 1639 | ||
1474 | map->lock(map->lock_arg); | 1640 | map->lock(map->lock_arg); |
1475 | 1641 | ||
1476 | ret = _regmap_raw_write(map, reg, val, val_len, true); | 1642 | map->async = true; |
1643 | |||
1644 | ret = _regmap_raw_write(map, reg, val, val_len); | ||
1645 | |||
1646 | map->async = false; | ||
1477 | 1647 | ||
1478 | map->unlock(map->lock_arg); | 1648 | map->unlock(map->lock_arg); |
1479 | 1649 | ||
@@ -1677,6 +1847,39 @@ int regmap_field_read(struct regmap_field *field, unsigned int *val) | |||
1677 | EXPORT_SYMBOL_GPL(regmap_field_read); | 1847 | EXPORT_SYMBOL_GPL(regmap_field_read); |
1678 | 1848 | ||
1679 | /** | 1849 | /** |
1850 | * regmap_fields_read(): Read a value to a single register field with port ID | ||
1851 | * | ||
1852 | * @field: Register field to read from | ||
1853 | * @id: port ID | ||
1854 | * @val: Pointer to store read value | ||
1855 | * | ||
1856 | * A value of zero will be returned on success, a negative errno will | ||
1857 | * be returned in error cases. | ||
1858 | */ | ||
1859 | int regmap_fields_read(struct regmap_field *field, unsigned int id, | ||
1860 | unsigned int *val) | ||
1861 | { | ||
1862 | int ret; | ||
1863 | unsigned int reg_val; | ||
1864 | |||
1865 | if (id >= field->id_size) | ||
1866 | return -EINVAL; | ||
1867 | |||
1868 | ret = regmap_read(field->regmap, | ||
1869 | field->reg + (field->id_offset * id), | ||
1870 | ®_val); | ||
1871 | if (ret != 0) | ||
1872 | return ret; | ||
1873 | |||
1874 | reg_val &= field->mask; | ||
1875 | reg_val >>= field->shift; | ||
1876 | *val = reg_val; | ||
1877 | |||
1878 | return ret; | ||
1879 | } | ||
1880 | EXPORT_SYMBOL_GPL(regmap_fields_read); | ||
1881 | |||
1882 | /** | ||
1680 | * regmap_bulk_read(): Read multiple registers from the device | 1883 | * regmap_bulk_read(): Read multiple registers from the device |
1681 | * | 1884 | * |
1682 | * @map: Register map to write to | 1885 | * @map: Register map to write to |
@@ -1788,6 +1991,41 @@ int regmap_update_bits(struct regmap *map, unsigned int reg, | |||
1788 | EXPORT_SYMBOL_GPL(regmap_update_bits); | 1991 | EXPORT_SYMBOL_GPL(regmap_update_bits); |
1789 | 1992 | ||
1790 | /** | 1993 | /** |
1994 | * regmap_update_bits_async: Perform a read/modify/write cycle on the register | ||
1995 | * map asynchronously | ||
1996 | * | ||
1997 | * @map: Register map to update | ||
1998 | * @reg: Register to update | ||
1999 | * @mask: Bitmask to change | ||
2000 | * @val: New value for bitmask | ||
2001 | * | ||
2002 | * With most buses the read must be done synchronously so this is most | ||
2003 | * useful for devices with a cache which do not need to interact with | ||
2004 | * the hardware to determine the current register value. | ||
2005 | * | ||
2006 | * Returns zero for success, a negative number on error. | ||
2007 | */ | ||
2008 | int regmap_update_bits_async(struct regmap *map, unsigned int reg, | ||
2009 | unsigned int mask, unsigned int val) | ||
2010 | { | ||
2011 | bool change; | ||
2012 | int ret; | ||
2013 | |||
2014 | map->lock(map->lock_arg); | ||
2015 | |||
2016 | map->async = true; | ||
2017 | |||
2018 | ret = _regmap_update_bits(map, reg, mask, val, &change); | ||
2019 | |||
2020 | map->async = false; | ||
2021 | |||
2022 | map->unlock(map->lock_arg); | ||
2023 | |||
2024 | return ret; | ||
2025 | } | ||
2026 | EXPORT_SYMBOL_GPL(regmap_update_bits_async); | ||
2027 | |||
2028 | /** | ||
1791 | * regmap_update_bits_check: Perform a read/modify/write cycle on the | 2029 | * regmap_update_bits_check: Perform a read/modify/write cycle on the |
1792 | * register map and report if updated | 2030 | * register map and report if updated |
1793 | * | 2031 | * |
@@ -1812,6 +2050,43 @@ int regmap_update_bits_check(struct regmap *map, unsigned int reg, | |||
1812 | } | 2050 | } |
1813 | EXPORT_SYMBOL_GPL(regmap_update_bits_check); | 2051 | EXPORT_SYMBOL_GPL(regmap_update_bits_check); |
1814 | 2052 | ||
2053 | /** | ||
2054 | * regmap_update_bits_check_async: Perform a read/modify/write cycle on the | ||
2055 | * register map asynchronously and report if | ||
2056 | * updated | ||
2057 | * | ||
2058 | * @map: Register map to update | ||
2059 | * @reg: Register to update | ||
2060 | * @mask: Bitmask to change | ||
2061 | * @val: New value for bitmask | ||
2062 | * @change: Boolean indicating if a write was done | ||
2063 | * | ||
2064 | * With most buses the read must be done synchronously so this is most | ||
2065 | * useful for devices with a cache which do not need to interact with | ||
2066 | * the hardware to determine the current register value. | ||
2067 | * | ||
2068 | * Returns zero for success, a negative number on error. | ||
2069 | */ | ||
2070 | int regmap_update_bits_check_async(struct regmap *map, unsigned int reg, | ||
2071 | unsigned int mask, unsigned int val, | ||
2072 | bool *change) | ||
2073 | { | ||
2074 | int ret; | ||
2075 | |||
2076 | map->lock(map->lock_arg); | ||
2077 | |||
2078 | map->async = true; | ||
2079 | |||
2080 | ret = _regmap_update_bits(map, reg, mask, val, change); | ||
2081 | |||
2082 | map->async = false; | ||
2083 | |||
2084 | map->unlock(map->lock_arg); | ||
2085 | |||
2086 | return ret; | ||
2087 | } | ||
2088 | EXPORT_SYMBOL_GPL(regmap_update_bits_check_async); | ||
2089 | |||
1815 | void regmap_async_complete_cb(struct regmap_async *async, int ret) | 2090 | void regmap_async_complete_cb(struct regmap_async *async, int ret) |
1816 | { | 2091 | { |
1817 | struct regmap *map = async->map; | 2092 | struct regmap *map = async->map; |
@@ -1820,8 +2095,7 @@ void regmap_async_complete_cb(struct regmap_async *async, int ret) | |||
1820 | trace_regmap_async_io_complete(map->dev); | 2095 | trace_regmap_async_io_complete(map->dev); |
1821 | 2096 | ||
1822 | spin_lock(&map->async_lock); | 2097 | spin_lock(&map->async_lock); |
1823 | 2098 | list_move(&async->list, &map->async_free); | |
1824 | list_del(&async->list); | ||
1825 | wake = list_empty(&map->async_list); | 2099 | wake = list_empty(&map->async_list); |
1826 | 2100 | ||
1827 | if (ret != 0) | 2101 | if (ret != 0) |
@@ -1829,8 +2103,6 @@ void regmap_async_complete_cb(struct regmap_async *async, int ret) | |||
1829 | 2103 | ||
1830 | spin_unlock(&map->async_lock); | 2104 | spin_unlock(&map->async_lock); |
1831 | 2105 | ||
1832 | schedule_work(&async->cleanup); | ||
1833 | |||
1834 | if (wake) | 2106 | if (wake) |
1835 | wake_up(&map->async_waitq); | 2107 | wake_up(&map->async_waitq); |
1836 | } | 2108 | } |
@@ -1906,6 +2178,7 @@ int regmap_register_patch(struct regmap *map, const struct reg_default *regs, | |||
1906 | bypass = map->cache_bypass; | 2178 | bypass = map->cache_bypass; |
1907 | 2179 | ||
1908 | map->cache_bypass = true; | 2180 | map->cache_bypass = true; |
2181 | map->async = true; | ||
1909 | 2182 | ||
1910 | /* Write out first; it's useful to apply even if we fail later. */ | 2183 | /* Write out first; it's useful to apply even if we fail later. */ |
1911 | for (i = 0; i < num_regs; i++) { | 2184 | for (i = 0; i < num_regs; i++) { |
@@ -1929,10 +2202,13 @@ int regmap_register_patch(struct regmap *map, const struct reg_default *regs, | |||
1929 | } | 2202 | } |
1930 | 2203 | ||
1931 | out: | 2204 | out: |
2205 | map->async = false; | ||
1932 | map->cache_bypass = bypass; | 2206 | map->cache_bypass = bypass; |
1933 | 2207 | ||
1934 | map->unlock(map->lock_arg); | 2208 | map->unlock(map->lock_arg); |
1935 | 2209 | ||
2210 | regmap_async_complete(map); | ||
2211 | |||
1936 | return ret; | 2212 | return ret; |
1937 | } | 2213 | } |
1938 | EXPORT_SYMBOL_GPL(regmap_register_patch); | 2214 | EXPORT_SYMBOL_GPL(regmap_register_patch); |