diff options
author | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2013-02-04 14:52:17 -0500 |
---|---|---|
committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2013-02-04 14:52:17 -0500 |
commit | 4c47c2b0f82c5ebe2187768b8ed05281d13b438e (patch) | |
tree | 9046ba012ad917a6edf46fe0056df56a99a3c758 | |
parent | 31522764c6b57e41b79220156efc5d208f2f841a (diff) | |
parent | f804fb562b0d9f4a8546fa2808d14e80aea8ff26 (diff) |
Merge tag 'async' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap into asoc-adsp
regmap: Add async I/O support
Allow drivers to take advantage of any support the underlying transports
may have for pipelining data.
-rw-r--r-- | drivers/base/regmap/internal.h | 18 | ||||
-rw-r--r-- | drivers/base/regmap/regmap-spi.c | 52 | ||||
-rw-r--r-- | drivers/base/regmap/regmap.c | 300 | ||||
-rw-r--r-- | include/linux/regmap.h | 28 |
4 files changed, 351 insertions, 47 deletions
diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h index 401d1919635a..202518641779 100644 --- a/drivers/base/regmap/internal.h +++ b/drivers/base/regmap/internal.h | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <linux/regmap.h> | 16 | #include <linux/regmap.h> |
17 | #include <linux/fs.h> | 17 | #include <linux/fs.h> |
18 | #include <linux/list.h> | 18 | #include <linux/list.h> |
19 | #include <linux/wait.h> | ||
19 | 20 | ||
20 | struct regmap; | 21 | struct regmap; |
21 | struct regcache_ops; | 22 | struct regcache_ops; |
@@ -39,6 +40,13 @@ struct regmap_format { | |||
39 | unsigned int (*parse_val)(void *buf); | 40 | unsigned int (*parse_val)(void *buf); |
40 | }; | 41 | }; |
41 | 42 | ||
43 | struct regmap_async { | ||
44 | struct list_head list; | ||
45 | struct work_struct cleanup; | ||
46 | struct regmap *map; | ||
47 | void *work_buf; | ||
48 | }; | ||
49 | |||
42 | struct regmap { | 50 | struct regmap { |
43 | struct mutex mutex; | 51 | struct mutex mutex; |
44 | spinlock_t spinlock; | 52 | spinlock_t spinlock; |
@@ -53,6 +61,11 @@ struct regmap { | |||
53 | void *bus_context; | 61 | void *bus_context; |
54 | const char *name; | 62 | const char *name; |
55 | 63 | ||
64 | spinlock_t async_lock; | ||
65 | wait_queue_head_t async_waitq; | ||
66 | struct list_head async_list; | ||
67 | int async_ret; | ||
68 | |||
56 | #ifdef CONFIG_DEBUG_FS | 69 | #ifdef CONFIG_DEBUG_FS |
57 | struct dentry *debugfs; | 70 | struct dentry *debugfs; |
58 | const char *debugfs_name; | 71 | const char *debugfs_name; |
@@ -74,6 +87,9 @@ struct regmap { | |||
74 | const struct regmap_access_table *volatile_table; | 87 | const struct regmap_access_table *volatile_table; |
75 | const struct regmap_access_table *precious_table; | 88 | const struct regmap_access_table *precious_table; |
76 | 89 | ||
90 | int (*reg_read)(void *context, unsigned int reg, unsigned int *val); | ||
91 | int (*reg_write)(void *context, unsigned int reg, unsigned int val); | ||
92 | |||
77 | u8 read_flag_mask; | 93 | u8 read_flag_mask; |
78 | u8 write_flag_mask; | 94 | u8 write_flag_mask; |
79 | 95 | ||
@@ -175,6 +191,8 @@ bool regcache_set_val(void *base, unsigned int idx, | |||
175 | unsigned int val, unsigned int word_size); | 191 | unsigned int val, unsigned int word_size); |
176 | int regcache_lookup_reg(struct regmap *map, unsigned int reg); | 192 | int regcache_lookup_reg(struct regmap *map, unsigned int reg); |
177 | 193 | ||
194 | void regmap_async_complete_cb(struct regmap_async *async, int ret); | ||
195 | |||
178 | extern struct regcache_ops regcache_rbtree_ops; | 196 | extern struct regcache_ops regcache_rbtree_ops; |
179 | extern struct regcache_ops regcache_lzo_ops; | 197 | extern struct regcache_ops regcache_lzo_ops; |
180 | 198 | ||
diff --git a/drivers/base/regmap/regmap-spi.c b/drivers/base/regmap/regmap-spi.c index ffa46a92ad33..913274b5f00a 100644 --- a/drivers/base/regmap/regmap-spi.c +++ b/drivers/base/regmap/regmap-spi.c | |||
@@ -15,6 +15,21 @@ | |||
15 | #include <linux/init.h> | 15 | #include <linux/init.h> |
16 | #include <linux/module.h> | 16 | #include <linux/module.h> |
17 | 17 | ||
18 | #include "internal.h" | ||
19 | |||
20 | struct regmap_async_spi { | ||
21 | struct regmap_async core; | ||
22 | struct spi_message m; | ||
23 | struct spi_transfer t[2]; | ||
24 | }; | ||
25 | |||
26 | static void regmap_spi_complete(void *data) | ||
27 | { | ||
28 | struct regmap_async_spi *async = data; | ||
29 | |||
30 | regmap_async_complete_cb(&async->core, async->m.status); | ||
31 | } | ||
32 | |||
18 | static int regmap_spi_write(void *context, const void *data, size_t count) | 33 | static int regmap_spi_write(void *context, const void *data, size_t count) |
19 | { | 34 | { |
20 | struct device *dev = context; | 35 | struct device *dev = context; |
@@ -40,6 +55,41 @@ static int regmap_spi_gather_write(void *context, | |||
40 | return spi_sync(spi, &m); | 55 | return spi_sync(spi, &m); |
41 | } | 56 | } |
42 | 57 | ||
58 | static int regmap_spi_async_write(void *context, | ||
59 | const void *reg, size_t reg_len, | ||
60 | const void *val, size_t val_len, | ||
61 | struct regmap_async *a) | ||
62 | { | ||
63 | struct regmap_async_spi *async = container_of(a, | ||
64 | struct regmap_async_spi, | ||
65 | core); | ||
66 | struct device *dev = context; | ||
67 | struct spi_device *spi = to_spi_device(dev); | ||
68 | |||
69 | async->t[0].tx_buf = reg; | ||
70 | async->t[0].len = reg_len; | ||
71 | async->t[1].tx_buf = val; | ||
72 | async->t[1].len = val_len; | ||
73 | |||
74 | spi_message_init(&async->m); | ||
75 | spi_message_add_tail(&async->t[0], &async->m); | ||
76 | spi_message_add_tail(&async->t[1], &async->m); | ||
77 | |||
78 | async->m.complete = regmap_spi_complete; | ||
79 | async->m.context = async; | ||
80 | |||
81 | return spi_async(spi, &async->m); | ||
82 | } | ||
83 | |||
84 | static struct regmap_async *regmap_spi_async_alloc(void) | ||
85 | { | ||
86 | struct regmap_async_spi *async_spi; | ||
87 | |||
88 | async_spi = kzalloc(sizeof(*async_spi), GFP_KERNEL); | ||
89 | |||
90 | return &async_spi->core; | ||
91 | } | ||
92 | |||
43 | static int regmap_spi_read(void *context, | 93 | static int regmap_spi_read(void *context, |
44 | const void *reg, size_t reg_size, | 94 | const void *reg, size_t reg_size, |
45 | void *val, size_t val_size) | 95 | void *val, size_t val_size) |
@@ -53,6 +103,8 @@ static int regmap_spi_read(void *context, | |||
53 | static struct regmap_bus regmap_spi = { | 103 | static struct regmap_bus regmap_spi = { |
54 | .write = regmap_spi_write, | 104 | .write = regmap_spi_write, |
55 | .gather_write = regmap_spi_gather_write, | 105 | .gather_write = regmap_spi_gather_write, |
106 | .async_write = regmap_spi_async_write, | ||
107 | .async_alloc = regmap_spi_async_alloc, | ||
56 | .read = regmap_spi_read, | 108 | .read = regmap_spi_read, |
57 | .read_flag_mask = 0x80, | 109 | .read_flag_mask = 0x80, |
58 | }; | 110 | }; |
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 42d5cb0f503f..6d1e756e90ad 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <linux/mutex.h> | 16 | #include <linux/mutex.h> |
17 | #include <linux/err.h> | 17 | #include <linux/err.h> |
18 | #include <linux/rbtree.h> | 18 | #include <linux/rbtree.h> |
19 | #include <linux/sched.h> | ||
19 | 20 | ||
20 | #define CREATE_TRACE_POINTS | 21 | #define CREATE_TRACE_POINTS |
21 | #include <trace/events/regmap.h> | 22 | #include <trace/events/regmap.h> |
@@ -34,6 +35,22 @@ static int _regmap_update_bits(struct regmap *map, unsigned int reg, | |||
34 | unsigned int mask, unsigned int val, | 35 | unsigned int mask, unsigned int val, |
35 | bool *change); | 36 | bool *change); |
36 | 37 | ||
38 | static int _regmap_bus_read(void *context, unsigned int reg, | ||
39 | unsigned int *val); | ||
40 | static int _regmap_bus_formatted_write(void *context, unsigned int reg, | ||
41 | unsigned int val); | ||
42 | static int _regmap_bus_raw_write(void *context, unsigned int reg, | ||
43 | unsigned int val); | ||
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 | |||
37 | bool regmap_reg_in_ranges(unsigned int reg, | 54 | bool regmap_reg_in_ranges(unsigned int reg, |
38 | const struct regmap_range *ranges, | 55 | const struct regmap_range *ranges, |
39 | unsigned int nranges) | 56 | unsigned int nranges) |
@@ -423,6 +440,10 @@ struct regmap *regmap_init(struct device *dev, | |||
423 | map->cache_type = config->cache_type; | 440 | map->cache_type = config->cache_type; |
424 | map->name = config->name; | 441 | map->name = config->name; |
425 | 442 | ||
443 | spin_lock_init(&map->async_lock); | ||
444 | INIT_LIST_HEAD(&map->async_list); | ||
445 | init_waitqueue_head(&map->async_waitq); | ||
446 | |||
426 | if (config->read_flag_mask || config->write_flag_mask) { | 447 | if (config->read_flag_mask || config->write_flag_mask) { |
427 | map->read_flag_mask = config->read_flag_mask; | 448 | map->read_flag_mask = config->read_flag_mask; |
428 | map->write_flag_mask = config->write_flag_mask; | 449 | map->write_flag_mask = config->write_flag_mask; |
@@ -430,6 +451,8 @@ struct regmap *regmap_init(struct device *dev, | |||
430 | map->read_flag_mask = bus->read_flag_mask; | 451 | map->read_flag_mask = bus->read_flag_mask; |
431 | } | 452 | } |
432 | 453 | ||
454 | map->reg_read = _regmap_bus_read; | ||
455 | |||
433 | reg_endian = config->reg_format_endian; | 456 | reg_endian = config->reg_format_endian; |
434 | if (reg_endian == REGMAP_ENDIAN_DEFAULT) | 457 | if (reg_endian == REGMAP_ENDIAN_DEFAULT) |
435 | reg_endian = bus->reg_format_endian_default; | 458 | reg_endian = bus->reg_format_endian_default; |
@@ -575,6 +598,11 @@ struct regmap *regmap_init(struct device *dev, | |||
575 | goto err_map; | 598 | goto err_map; |
576 | } | 599 | } |
577 | 600 | ||
601 | if (map->format.format_write) | ||
602 | map->reg_write = _regmap_bus_formatted_write; | ||
603 | else if (map->format.format_val) | ||
604 | map->reg_write = _regmap_bus_raw_write; | ||
605 | |||
578 | map->range_tree = RB_ROOT; | 606 | map->range_tree = RB_ROOT; |
579 | for (i = 0; i < config->num_ranges; i++) { | 607 | for (i = 0; i < config->num_ranges; i++) { |
580 | const struct regmap_range_cfg *range_cfg = &config->ranges[i]; | 608 | const struct regmap_range_cfg *range_cfg = &config->ranges[i]; |
@@ -870,10 +898,13 @@ static int _regmap_select_page(struct regmap *map, unsigned int *reg, | |||
870 | } | 898 | } |
871 | 899 | ||
872 | static int _regmap_raw_write(struct regmap *map, unsigned int reg, | 900 | static int _regmap_raw_write(struct regmap *map, unsigned int reg, |
873 | const void *val, size_t val_len) | 901 | const void *val, size_t val_len, bool async) |
874 | { | 902 | { |
875 | struct regmap_range_node *range; | 903 | struct regmap_range_node *range; |
904 | unsigned long flags; | ||
876 | u8 *u8 = map->work_buf; | 905 | u8 *u8 = map->work_buf; |
906 | void *work_val = map->work_buf + map->format.reg_bytes + | ||
907 | map->format.pad_bytes; | ||
877 | void *buf; | 908 | void *buf; |
878 | int ret = -ENOTSUPP; | 909 | int ret = -ENOTSUPP; |
879 | size_t len; | 910 | size_t len; |
@@ -918,7 +949,7 @@ static int _regmap_raw_write(struct regmap *map, unsigned int reg, | |||
918 | dev_dbg(map->dev, "Writing window %d/%zu\n", | 949 | dev_dbg(map->dev, "Writing window %d/%zu\n", |
919 | win_residue, val_len / map->format.val_bytes); | 950 | win_residue, val_len / map->format.val_bytes); |
920 | ret = _regmap_raw_write(map, reg, val, win_residue * | 951 | ret = _regmap_raw_write(map, reg, val, win_residue * |
921 | map->format.val_bytes); | 952 | map->format.val_bytes, async); |
922 | if (ret != 0) | 953 | if (ret != 0) |
923 | return ret; | 954 | return ret; |
924 | 955 | ||
@@ -941,6 +972,50 @@ static int _regmap_raw_write(struct regmap *map, unsigned int reg, | |||
941 | 972 | ||
942 | u8[0] |= map->write_flag_mask; | 973 | u8[0] |= map->write_flag_mask; |
943 | 974 | ||
975 | if (async && map->bus->async_write) { | ||
976 | struct regmap_async *async = map->bus->async_alloc(); | ||
977 | if (!async) | ||
978 | return -ENOMEM; | ||
979 | |||
980 | async->work_buf = kzalloc(map->format.buf_size, | ||
981 | GFP_KERNEL | GFP_DMA); | ||
982 | if (!async->work_buf) { | ||
983 | kfree(async); | ||
984 | return -ENOMEM; | ||
985 | } | ||
986 | |||
987 | INIT_WORK(&async->cleanup, async_cleanup); | ||
988 | async->map = map; | ||
989 | |||
990 | /* If the caller supplied the value we can use it safely. */ | ||
991 | memcpy(async->work_buf, map->work_buf, map->format.pad_bytes + | ||
992 | map->format.reg_bytes + map->format.val_bytes); | ||
993 | if (val == work_val) | ||
994 | val = async->work_buf + map->format.pad_bytes + | ||
995 | map->format.reg_bytes; | ||
996 | |||
997 | spin_lock_irqsave(&map->async_lock, flags); | ||
998 | list_add_tail(&async->list, &map->async_list); | ||
999 | spin_unlock_irqrestore(&map->async_lock, flags); | ||
1000 | |||
1001 | ret = map->bus->async_write(map->bus_context, async->work_buf, | ||
1002 | map->format.reg_bytes + | ||
1003 | map->format.pad_bytes, | ||
1004 | val, val_len, async); | ||
1005 | |||
1006 | if (ret != 0) { | ||
1007 | dev_err(map->dev, "Failed to schedule write: %d\n", | ||
1008 | ret); | ||
1009 | |||
1010 | spin_lock_irqsave(&map->async_lock, flags); | ||
1011 | list_del(&async->list); | ||
1012 | spin_unlock_irqrestore(&map->async_lock, flags); | ||
1013 | |||
1014 | kfree(async->work_buf); | ||
1015 | kfree(async); | ||
1016 | } | ||
1017 | } | ||
1018 | |||
944 | trace_regmap_hw_write_start(map->dev, reg, | 1019 | trace_regmap_hw_write_start(map->dev, reg, |
945 | val_len / map->format.val_bytes); | 1020 | val_len / map->format.val_bytes); |
946 | 1021 | ||
@@ -948,8 +1023,7 @@ static int _regmap_raw_write(struct regmap *map, unsigned int reg, | |||
948 | * send the work_buf directly, otherwise try to do a gather | 1023 | * send the work_buf directly, otherwise try to do a gather |
949 | * write. | 1024 | * write. |
950 | */ | 1025 | */ |
951 | if (val == (map->work_buf + map->format.pad_bytes + | 1026 | if (val == work_val) |
952 | map->format.reg_bytes)) | ||
953 | ret = map->bus->write(map->bus_context, map->work_buf, | 1027 | ret = map->bus->write(map->bus_context, map->work_buf, |
954 | map->format.reg_bytes + | 1028 | map->format.reg_bytes + |
955 | map->format.pad_bytes + | 1029 | map->format.pad_bytes + |
@@ -981,12 +1055,54 @@ static int _regmap_raw_write(struct regmap *map, unsigned int reg, | |||
981 | return ret; | 1055 | return ret; |
982 | } | 1056 | } |
983 | 1057 | ||
1058 | static int _regmap_bus_formatted_write(void *context, unsigned int reg, | ||
1059 | unsigned int val) | ||
1060 | { | ||
1061 | int ret; | ||
1062 | struct regmap_range_node *range; | ||
1063 | struct regmap *map = context; | ||
1064 | |||
1065 | BUG_ON(!map->format.format_write); | ||
1066 | |||
1067 | range = _regmap_range_lookup(map, reg); | ||
1068 | if (range) { | ||
1069 | ret = _regmap_select_page(map, ®, range, 1); | ||
1070 | if (ret != 0) | ||
1071 | return ret; | ||
1072 | } | ||
1073 | |||
1074 | map->format.format_write(map, reg, val); | ||
1075 | |||
1076 | trace_regmap_hw_write_start(map->dev, reg, 1); | ||
1077 | |||
1078 | ret = map->bus->write(map->bus_context, map->work_buf, | ||
1079 | map->format.buf_size); | ||
1080 | |||
1081 | trace_regmap_hw_write_done(map->dev, reg, 1); | ||
1082 | |||
1083 | return ret; | ||
1084 | } | ||
1085 | |||
1086 | static int _regmap_bus_raw_write(void *context, unsigned int reg, | ||
1087 | unsigned int val) | ||
1088 | { | ||
1089 | struct regmap *map = context; | ||
1090 | |||
1091 | BUG_ON(!map->format.format_val); | ||
1092 | |||
1093 | map->format.format_val(map->work_buf + map->format.reg_bytes | ||
1094 | + map->format.pad_bytes, val, 0); | ||
1095 | return _regmap_raw_write(map, reg, | ||
1096 | map->work_buf + | ||
1097 | map->format.reg_bytes + | ||
1098 | map->format.pad_bytes, | ||
1099 | map->format.val_bytes, false); | ||
1100 | } | ||
1101 | |||
984 | int _regmap_write(struct regmap *map, unsigned int reg, | 1102 | int _regmap_write(struct regmap *map, unsigned int reg, |
985 | unsigned int val) | 1103 | unsigned int val) |
986 | { | 1104 | { |
987 | struct regmap_range_node *range; | ||
988 | int ret; | 1105 | int ret; |
989 | BUG_ON(!map->format.format_write && !map->format.format_val); | ||
990 | 1106 | ||
991 | if (!map->cache_bypass && map->format.format_write) { | 1107 | if (!map->cache_bypass && map->format.format_write) { |
992 | ret = regcache_write(map, reg, val); | 1108 | ret = regcache_write(map, reg, val); |
@@ -1005,33 +1121,7 @@ int _regmap_write(struct regmap *map, unsigned int reg, | |||
1005 | 1121 | ||
1006 | trace_regmap_reg_write(map->dev, reg, val); | 1122 | trace_regmap_reg_write(map->dev, reg, val); |
1007 | 1123 | ||
1008 | if (map->format.format_write) { | 1124 | return map->reg_write(map, reg, val); |
1009 | range = _regmap_range_lookup(map, reg); | ||
1010 | if (range) { | ||
1011 | ret = _regmap_select_page(map, ®, range, 1); | ||
1012 | if (ret != 0) | ||
1013 | return ret; | ||
1014 | } | ||
1015 | |||
1016 | map->format.format_write(map, reg, val); | ||
1017 | |||
1018 | trace_regmap_hw_write_start(map->dev, reg, 1); | ||
1019 | |||
1020 | ret = map->bus->write(map->bus_context, map->work_buf, | ||
1021 | map->format.buf_size); | ||
1022 | |||
1023 | trace_regmap_hw_write_done(map->dev, reg, 1); | ||
1024 | |||
1025 | return ret; | ||
1026 | } else { | ||
1027 | map->format.format_val(map->work_buf + map->format.reg_bytes | ||
1028 | + map->format.pad_bytes, val, 0); | ||
1029 | return _regmap_raw_write(map, reg, | ||
1030 | map->work_buf + | ||
1031 | map->format.reg_bytes + | ||
1032 | map->format.pad_bytes, | ||
1033 | map->format.val_bytes); | ||
1034 | } | ||
1035 | } | 1125 | } |
1036 | 1126 | ||
1037 | /** | 1127 | /** |
@@ -1089,7 +1179,7 @@ int regmap_raw_write(struct regmap *map, unsigned int reg, | |||
1089 | 1179 | ||
1090 | map->lock(map->lock_arg); | 1180 | map->lock(map->lock_arg); |
1091 | 1181 | ||
1092 | ret = _regmap_raw_write(map, reg, val, val_len); | 1182 | ret = _regmap_raw_write(map, reg, val, val_len, false); |
1093 | 1183 | ||
1094 | map->unlock(map->lock_arg); | 1184 | map->unlock(map->lock_arg); |
1095 | 1185 | ||
@@ -1145,14 +1235,15 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val, | |||
1145 | if (map->use_single_rw) { | 1235 | if (map->use_single_rw) { |
1146 | for (i = 0; i < val_count; i++) { | 1236 | for (i = 0; i < val_count; i++) { |
1147 | ret = regmap_raw_write(map, | 1237 | ret = regmap_raw_write(map, |
1148 | reg + (i * map->reg_stride), | 1238 | reg + (i * map->reg_stride), |
1149 | val + (i * val_bytes), | 1239 | val + (i * val_bytes), |
1150 | val_bytes); | 1240 | val_bytes); |
1151 | if (ret != 0) | 1241 | if (ret != 0) |
1152 | return ret; | 1242 | return ret; |
1153 | } | 1243 | } |
1154 | } else { | 1244 | } else { |
1155 | ret = _regmap_raw_write(map, reg, wval, val_bytes * val_count); | 1245 | ret = _regmap_raw_write(map, reg, wval, val_bytes * val_count, |
1246 | false); | ||
1156 | } | 1247 | } |
1157 | 1248 | ||
1158 | if (val_bytes != 1) | 1249 | if (val_bytes != 1) |
@@ -1164,6 +1255,48 @@ out: | |||
1164 | } | 1255 | } |
1165 | EXPORT_SYMBOL_GPL(regmap_bulk_write); | 1256 | EXPORT_SYMBOL_GPL(regmap_bulk_write); |
1166 | 1257 | ||
1258 | /** | ||
1259 | * regmap_raw_write_async(): Write raw values to one or more registers | ||
1260 | * asynchronously | ||
1261 | * | ||
1262 | * @map: Register map to write to | ||
1263 | * @reg: Initial register to write to | ||
1264 | * @val: Block of data to be written, laid out for direct transmission to the | ||
1265 | * device. Must be valid until regmap_async_complete() is called. | ||
1266 | * @val_len: Length of data pointed to by val. | ||
1267 | * | ||
1268 | * This function is intended to be used for things like firmware | ||
1269 | * download where a large block of data needs to be transferred to the | ||
1270 | * device. No formatting will be done on the data provided. | ||
1271 | * | ||
1272 | * If supported by the underlying bus the write will be scheduled | ||
1273 | * asynchronously, helping maximise I/O speed on higher speed buses | ||
1274 | * like SPI. regmap_async_complete() can be called to ensure that all | ||
1275 | * asynchrnous writes have been completed. | ||
1276 | * | ||
1277 | * A value of zero will be returned on success, a negative errno will | ||
1278 | * be returned in error cases. | ||
1279 | */ | ||
1280 | int regmap_raw_write_async(struct regmap *map, unsigned int reg, | ||
1281 | const void *val, size_t val_len) | ||
1282 | { | ||
1283 | int ret; | ||
1284 | |||
1285 | if (val_len % map->format.val_bytes) | ||
1286 | return -EINVAL; | ||
1287 | if (reg % map->reg_stride) | ||
1288 | return -EINVAL; | ||
1289 | |||
1290 | map->lock(map->lock_arg); | ||
1291 | |||
1292 | ret = _regmap_raw_write(map, reg, val, val_len, true); | ||
1293 | |||
1294 | map->unlock(map->lock_arg); | ||
1295 | |||
1296 | return ret; | ||
1297 | } | ||
1298 | EXPORT_SYMBOL_GPL(regmap_raw_write_async); | ||
1299 | |||
1167 | static int _regmap_raw_read(struct regmap *map, unsigned int reg, void *val, | 1300 | static int _regmap_raw_read(struct regmap *map, unsigned int reg, void *val, |
1168 | unsigned int val_len) | 1301 | unsigned int val_len) |
1169 | { | 1302 | { |
@@ -1202,10 +1335,27 @@ static int _regmap_raw_read(struct regmap *map, unsigned int reg, void *val, | |||
1202 | return ret; | 1335 | return ret; |
1203 | } | 1336 | } |
1204 | 1337 | ||
1338 | static int _regmap_bus_read(void *context, unsigned int reg, | ||
1339 | unsigned int *val) | ||
1340 | { | ||
1341 | int ret; | ||
1342 | struct regmap *map = context; | ||
1343 | |||
1344 | if (!map->format.parse_val) | ||
1345 | return -EINVAL; | ||
1346 | |||
1347 | ret = _regmap_raw_read(map, reg, map->work_buf, map->format.val_bytes); | ||
1348 | if (ret == 0) | ||
1349 | *val = map->format.parse_val(map->work_buf); | ||
1350 | |||
1351 | return ret; | ||
1352 | } | ||
1353 | |||
1205 | static int _regmap_read(struct regmap *map, unsigned int reg, | 1354 | static int _regmap_read(struct regmap *map, unsigned int reg, |
1206 | unsigned int *val) | 1355 | unsigned int *val) |
1207 | { | 1356 | { |
1208 | int ret; | 1357 | int ret; |
1358 | BUG_ON(!map->reg_read); | ||
1209 | 1359 | ||
1210 | if (!map->cache_bypass) { | 1360 | if (!map->cache_bypass) { |
1211 | ret = regcache_read(map, reg, val); | 1361 | ret = regcache_read(map, reg, val); |
@@ -1213,26 +1363,21 @@ static int _regmap_read(struct regmap *map, unsigned int reg, | |||
1213 | return 0; | 1363 | return 0; |
1214 | } | 1364 | } |
1215 | 1365 | ||
1216 | if (!map->format.parse_val) | ||
1217 | return -EINVAL; | ||
1218 | |||
1219 | if (map->cache_only) | 1366 | if (map->cache_only) |
1220 | return -EBUSY; | 1367 | return -EBUSY; |
1221 | 1368 | ||
1222 | ret = _regmap_raw_read(map, reg, map->work_buf, map->format.val_bytes); | 1369 | ret = map->reg_read(map, reg, val); |
1223 | if (ret == 0) { | 1370 | if (ret == 0) { |
1224 | *val = map->format.parse_val(map->work_buf); | ||
1225 | |||
1226 | #ifdef LOG_DEVICE | 1371 | #ifdef LOG_DEVICE |
1227 | if (strcmp(dev_name(map->dev), LOG_DEVICE) == 0) | 1372 | if (strcmp(dev_name(map->dev), LOG_DEVICE) == 0) |
1228 | dev_info(map->dev, "%x => %x\n", reg, *val); | 1373 | dev_info(map->dev, "%x => %x\n", reg, *val); |
1229 | #endif | 1374 | #endif |
1230 | 1375 | ||
1231 | trace_regmap_reg_read(map->dev, reg, *val); | 1376 | trace_regmap_reg_read(map->dev, reg, *val); |
1232 | } | ||
1233 | 1377 | ||
1234 | if (ret == 0 && !map->cache_bypass) | 1378 | if (!map->cache_bypass) |
1235 | regcache_write(map, reg, *val); | 1379 | regcache_write(map, reg, *val); |
1380 | } | ||
1236 | 1381 | ||
1237 | return ret; | 1382 | return ret; |
1238 | } | 1383 | } |
@@ -1450,6 +1595,67 @@ int regmap_update_bits_check(struct regmap *map, unsigned int reg, | |||
1450 | } | 1595 | } |
1451 | EXPORT_SYMBOL_GPL(regmap_update_bits_check); | 1596 | EXPORT_SYMBOL_GPL(regmap_update_bits_check); |
1452 | 1597 | ||
1598 | void regmap_async_complete_cb(struct regmap_async *async, int ret) | ||
1599 | { | ||
1600 | struct regmap *map = async->map; | ||
1601 | bool wake; | ||
1602 | |||
1603 | spin_lock(&map->async_lock); | ||
1604 | |||
1605 | list_del(&async->list); | ||
1606 | wake = list_empty(&map->async_list); | ||
1607 | |||
1608 | if (ret != 0) | ||
1609 | map->async_ret = ret; | ||
1610 | |||
1611 | spin_unlock(&map->async_lock); | ||
1612 | |||
1613 | schedule_work(&async->cleanup); | ||
1614 | |||
1615 | if (wake) | ||
1616 | wake_up(&map->async_waitq); | ||
1617 | } | ||
1618 | EXPORT_SYMBOL_GPL(regmap_async_complete_cb); | ||
1619 | |||
1620 | static int regmap_async_is_done(struct regmap *map) | ||
1621 | { | ||
1622 | unsigned long flags; | ||
1623 | int ret; | ||
1624 | |||
1625 | spin_lock_irqsave(&map->async_lock, flags); | ||
1626 | ret = list_empty(&map->async_list); | ||
1627 | spin_unlock_irqrestore(&map->async_lock, flags); | ||
1628 | |||
1629 | return ret; | ||
1630 | } | ||
1631 | |||
1632 | /** | ||
1633 | * regmap_async_complete: Ensure all asynchronous I/O has completed. | ||
1634 | * | ||
1635 | * @map: Map to operate on. | ||
1636 | * | ||
1637 | * Blocks until any pending asynchronous I/O has completed. Returns | ||
1638 | * an error code for any failed I/O operations. | ||
1639 | */ | ||
1640 | int regmap_async_complete(struct regmap *map) | ||
1641 | { | ||
1642 | unsigned long flags; | ||
1643 | int ret; | ||
1644 | |||
1645 | /* Nothing to do with no async support */ | ||
1646 | if (!map->bus->async_write) | ||
1647 | return 0; | ||
1648 | |||
1649 | wait_event(map->async_waitq, regmap_async_is_done(map)); | ||
1650 | |||
1651 | spin_lock_irqsave(&map->async_lock, flags); | ||
1652 | ret = map->async_ret; | ||
1653 | map->async_ret = 0; | ||
1654 | spin_unlock_irqrestore(&map->async_lock, flags); | ||
1655 | |||
1656 | return ret; | ||
1657 | } | ||
1658 | |||
1453 | /** | 1659 | /** |
1454 | * regmap_register_patch: Register and apply register updates to be applied | 1660 | * regmap_register_patch: Register and apply register updates to be applied |
1455 | * on device initialistion | 1661 | * on device initialistion |
diff --git a/include/linux/regmap.h b/include/linux/regmap.h index b7e95bf942c9..f9b7fbe35ab1 100644 --- a/include/linux/regmap.h +++ b/include/linux/regmap.h | |||
@@ -235,14 +235,21 @@ struct regmap_range_cfg { | |||
235 | unsigned int window_len; | 235 | unsigned int window_len; |
236 | }; | 236 | }; |
237 | 237 | ||
238 | struct regmap_async; | ||
239 | |||
238 | typedef int (*regmap_hw_write)(void *context, const void *data, | 240 | typedef int (*regmap_hw_write)(void *context, const void *data, |
239 | size_t count); | 241 | size_t count); |
240 | typedef int (*regmap_hw_gather_write)(void *context, | 242 | typedef int (*regmap_hw_gather_write)(void *context, |
241 | const void *reg, size_t reg_len, | 243 | const void *reg, size_t reg_len, |
242 | const void *val, size_t val_len); | 244 | const void *val, size_t val_len); |
245 | typedef int (*regmap_hw_async_write)(void *context, | ||
246 | const void *reg, size_t reg_len, | ||
247 | const void *val, size_t val_len, | ||
248 | struct regmap_async *async); | ||
243 | typedef int (*regmap_hw_read)(void *context, | 249 | typedef int (*regmap_hw_read)(void *context, |
244 | const void *reg_buf, size_t reg_size, | 250 | const void *reg_buf, size_t reg_size, |
245 | void *val_buf, size_t val_size); | 251 | void *val_buf, size_t val_size); |
252 | typedef struct regmap_async *(*regmap_hw_async_alloc)(void); | ||
246 | typedef void (*regmap_hw_free_context)(void *context); | 253 | typedef void (*regmap_hw_free_context)(void *context); |
247 | 254 | ||
248 | /** | 255 | /** |
@@ -255,8 +262,11 @@ typedef void (*regmap_hw_free_context)(void *context); | |||
255 | * @write: Write operation. | 262 | * @write: Write operation. |
256 | * @gather_write: Write operation with split register/value, return -ENOTSUPP | 263 | * @gather_write: Write operation with split register/value, return -ENOTSUPP |
257 | * if not implemented on a given device. | 264 | * if not implemented on a given device. |
265 | * @async_write: Write operation which completes asynchronously, optional and | ||
266 | * must serialise with respect to non-async I/O. | ||
258 | * @read: Read operation. Data is returned in the buffer used to transmit | 267 | * @read: Read operation. Data is returned in the buffer used to transmit |
259 | * data. | 268 | * data. |
269 | * @async_alloc: Allocate a regmap_async() structure. | ||
260 | * @read_flag_mask: Mask to be set in the top byte of the register when doing | 270 | * @read_flag_mask: Mask to be set in the top byte of the register when doing |
261 | * a read. | 271 | * a read. |
262 | * @reg_format_endian_default: Default endianness for formatted register | 272 | * @reg_format_endian_default: Default endianness for formatted register |
@@ -265,13 +275,16 @@ typedef void (*regmap_hw_free_context)(void *context); | |||
265 | * @val_format_endian_default: Default endianness for formatted register | 275 | * @val_format_endian_default: Default endianness for formatted register |
266 | * values. Used when the regmap_config specifies DEFAULT. If this is | 276 | * values. Used when the regmap_config specifies DEFAULT. If this is |
267 | * DEFAULT, BIG is assumed. | 277 | * DEFAULT, BIG is assumed. |
278 | * @async_size: Size of struct used for async work. | ||
268 | */ | 279 | */ |
269 | struct regmap_bus { | 280 | struct regmap_bus { |
270 | bool fast_io; | 281 | bool fast_io; |
271 | regmap_hw_write write; | 282 | regmap_hw_write write; |
272 | regmap_hw_gather_write gather_write; | 283 | regmap_hw_gather_write gather_write; |
284 | regmap_hw_async_write async_write; | ||
273 | regmap_hw_read read; | 285 | regmap_hw_read read; |
274 | regmap_hw_free_context free_context; | 286 | regmap_hw_free_context free_context; |
287 | regmap_hw_async_alloc async_alloc; | ||
275 | u8 read_flag_mask; | 288 | u8 read_flag_mask; |
276 | enum regmap_endian reg_format_endian_default; | 289 | enum regmap_endian reg_format_endian_default; |
277 | enum regmap_endian val_format_endian_default; | 290 | enum regmap_endian val_format_endian_default; |
@@ -310,6 +323,8 @@ int regmap_raw_write(struct regmap *map, unsigned int reg, | |||
310 | const void *val, size_t val_len); | 323 | const void *val, size_t val_len); |
311 | int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val, | 324 | int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val, |
312 | size_t val_count); | 325 | size_t val_count); |
326 | int regmap_raw_write_async(struct regmap *map, unsigned int reg, | ||
327 | const void *val, size_t val_len); | ||
313 | int regmap_read(struct regmap *map, unsigned int reg, unsigned int *val); | 328 | int regmap_read(struct regmap *map, unsigned int reg, unsigned int *val); |
314 | int regmap_raw_read(struct regmap *map, unsigned int reg, | 329 | int regmap_raw_read(struct regmap *map, unsigned int reg, |
315 | void *val, size_t val_len); | 330 | void *val, size_t val_len); |
@@ -321,6 +336,7 @@ int regmap_update_bits_check(struct regmap *map, unsigned int reg, | |||
321 | unsigned int mask, unsigned int val, | 336 | unsigned int mask, unsigned int val, |
322 | bool *change); | 337 | bool *change); |
323 | int regmap_get_val_bytes(struct regmap *map); | 338 | int regmap_get_val_bytes(struct regmap *map); |
339 | int regmap_async_complete(struct regmap *map); | ||
324 | 340 | ||
325 | int regcache_sync(struct regmap *map); | 341 | int regcache_sync(struct regmap *map); |
326 | int regcache_sync_region(struct regmap *map, unsigned int min, | 342 | int regcache_sync_region(struct regmap *map, unsigned int min, |
@@ -422,6 +438,13 @@ static inline int regmap_raw_write(struct regmap *map, unsigned int reg, | |||
422 | return -EINVAL; | 438 | return -EINVAL; |
423 | } | 439 | } |
424 | 440 | ||
441 | static inline int regmap_raw_write_async(struct regmap *map, unsigned int reg, | ||
442 | const void *val, size_t val_len) | ||
443 | { | ||
444 | WARN_ONCE(1, "regmap API is disabled"); | ||
445 | return -EINVAL; | ||
446 | } | ||
447 | |||
425 | static inline int regmap_bulk_write(struct regmap *map, unsigned int reg, | 448 | static inline int regmap_bulk_write(struct regmap *map, unsigned int reg, |
426 | const void *val, size_t val_count) | 449 | const void *val, size_t val_count) |
427 | { | 450 | { |
@@ -500,6 +523,11 @@ static inline void regcache_mark_dirty(struct regmap *map) | |||
500 | WARN_ONCE(1, "regmap API is disabled"); | 523 | WARN_ONCE(1, "regmap API is disabled"); |
501 | } | 524 | } |
502 | 525 | ||
526 | static inline void regmap_async_complete(struct regmap *map) | ||
527 | { | ||
528 | WARN_ONCE(1, "regmap API is disabled"); | ||
529 | } | ||
530 | |||
503 | static inline int regmap_register_patch(struct regmap *map, | 531 | static inline int regmap_register_patch(struct regmap *map, |
504 | const struct reg_default *regs, | 532 | const struct reg_default *regs, |
505 | int num_regs) | 533 | int num_regs) |