Commit 0d4529c534c1c664f25088eb5f5b4d7ce0ee2510
Committed by
Mark Brown
1 parent
ddffeb8c4d
Exists in
smarc-l5.0.0_1.0.0-ga
and in
5 other branches
regmap: make lock/unlock functions customizable
It is sometimes convenient for a regmap user to override the standard regmap lock/unlock functions with custom functions. For instance this can be useful in case an already existing spinlock or mutex has to be used for locking a set of registers instead of the internal regmap spinlock/mutex. Note that the fast_io field of struct regmap_bus is ignored in case custom locking functions are used. Signed-off-by: Davide Ciminaghi <ciminaghi@gnudd.com> Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Showing 3 changed files with 54 additions and 31 deletions Side-by-side Diff
drivers/base/regmap/internal.h
... | ... | @@ -31,14 +31,12 @@ |
31 | 31 | unsigned int (*parse_val)(void *buf); |
32 | 32 | }; |
33 | 33 | |
34 | -typedef void (*regmap_lock)(struct regmap *map); | |
35 | -typedef void (*regmap_unlock)(struct regmap *map); | |
36 | - | |
37 | 34 | struct regmap { |
38 | 35 | struct mutex mutex; |
39 | 36 | spinlock_t spinlock; |
40 | 37 | regmap_lock lock; |
41 | 38 | regmap_unlock unlock; |
39 | + void *lock_arg; /* This is passed to lock/unlock functions */ | |
42 | 40 | |
43 | 41 | struct device *dev; /* Device we do I/O on */ |
44 | 42 | void *work_buf; /* Scratch buffer used to format I/O */ |
drivers/base/regmap/regmap.c
... | ... | @@ -214,23 +214,27 @@ |
214 | 214 | return *(u32 *)buf; |
215 | 215 | } |
216 | 216 | |
217 | -static void regmap_lock_mutex(struct regmap *map) | |
217 | +static void regmap_lock_mutex(void *__map) | |
218 | 218 | { |
219 | + struct regmap *map = __map; | |
219 | 220 | mutex_lock(&map->mutex); |
220 | 221 | } |
221 | 222 | |
222 | -static void regmap_unlock_mutex(struct regmap *map) | |
223 | +static void regmap_unlock_mutex(void *__map) | |
223 | 224 | { |
225 | + struct regmap *map = __map; | |
224 | 226 | mutex_unlock(&map->mutex); |
225 | 227 | } |
226 | 228 | |
227 | -static void regmap_lock_spinlock(struct regmap *map) | |
229 | +static void regmap_lock_spinlock(void *__map) | |
228 | 230 | { |
231 | + struct regmap *map = __map; | |
229 | 232 | spin_lock(&map->spinlock); |
230 | 233 | } |
231 | 234 | |
232 | -static void regmap_unlock_spinlock(struct regmap *map) | |
235 | +static void regmap_unlock_spinlock(void *__map) | |
233 | 236 | { |
237 | + struct regmap *map = __map; | |
234 | 238 | spin_unlock(&map->spinlock); |
235 | 239 | } |
236 | 240 | |
237 | 241 | |
... | ... | @@ -335,14 +339,21 @@ |
335 | 339 | goto err; |
336 | 340 | } |
337 | 341 | |
338 | - if (bus->fast_io) { | |
339 | - spin_lock_init(&map->spinlock); | |
340 | - map->lock = regmap_lock_spinlock; | |
341 | - map->unlock = regmap_unlock_spinlock; | |
342 | + if (config->lock && config->unlock) { | |
343 | + map->lock = config->lock; | |
344 | + map->unlock = config->unlock; | |
345 | + map->lock_arg = config->lock_arg; | |
342 | 346 | } else { |
343 | - mutex_init(&map->mutex); | |
344 | - map->lock = regmap_lock_mutex; | |
345 | - map->unlock = regmap_unlock_mutex; | |
347 | + if (bus->fast_io) { | |
348 | + spin_lock_init(&map->spinlock); | |
349 | + map->lock = regmap_lock_spinlock; | |
350 | + map->unlock = regmap_unlock_spinlock; | |
351 | + } else { | |
352 | + mutex_init(&map->mutex); | |
353 | + map->lock = regmap_lock_mutex; | |
354 | + map->unlock = regmap_unlock_mutex; | |
355 | + } | |
356 | + map->lock_arg = map; | |
346 | 357 | } |
347 | 358 | map->format.reg_bytes = DIV_ROUND_UP(config->reg_bits, 8); |
348 | 359 | map->format.pad_bytes = config->pad_bits / 8; |
349 | 360 | |
... | ... | @@ -939,11 +950,11 @@ |
939 | 950 | if (reg % map->reg_stride) |
940 | 951 | return -EINVAL; |
941 | 952 | |
942 | - map->lock(map); | |
953 | + map->lock(map->lock_arg); | |
943 | 954 | |
944 | 955 | ret = _regmap_write(map, reg, val); |
945 | 956 | |
946 | - map->unlock(map); | |
957 | + map->unlock(map->lock_arg); | |
947 | 958 | |
948 | 959 | return ret; |
949 | 960 | } |
950 | 961 | |
... | ... | @@ -975,11 +986,11 @@ |
975 | 986 | if (reg % map->reg_stride) |
976 | 987 | return -EINVAL; |
977 | 988 | |
978 | - map->lock(map); | |
989 | + map->lock(map->lock_arg); | |
979 | 990 | |
980 | 991 | ret = _regmap_raw_write(map, reg, val, val_len); |
981 | 992 | |
982 | - map->unlock(map); | |
993 | + map->unlock(map->lock_arg); | |
983 | 994 | |
984 | 995 | return ret; |
985 | 996 | } |
... | ... | @@ -1011,7 +1022,7 @@ |
1011 | 1022 | if (reg % map->reg_stride) |
1012 | 1023 | return -EINVAL; |
1013 | 1024 | |
1014 | - map->lock(map); | |
1025 | + map->lock(map->lock_arg); | |
1015 | 1026 | |
1016 | 1027 | /* No formatting is require if val_byte is 1 */ |
1017 | 1028 | if (val_bytes == 1) { |
... | ... | @@ -1047,7 +1058,7 @@ |
1047 | 1058 | kfree(wval); |
1048 | 1059 | |
1049 | 1060 | out: |
1050 | - map->unlock(map); | |
1061 | + map->unlock(map->lock_arg); | |
1051 | 1062 | return ret; |
1052 | 1063 | } |
1053 | 1064 | EXPORT_SYMBOL_GPL(regmap_bulk_write); |
1054 | 1065 | |
... | ... | @@ -1137,11 +1148,11 @@ |
1137 | 1148 | if (reg % map->reg_stride) |
1138 | 1149 | return -EINVAL; |
1139 | 1150 | |
1140 | - map->lock(map); | |
1151 | + map->lock(map->lock_arg); | |
1141 | 1152 | |
1142 | 1153 | ret = _regmap_read(map, reg, val); |
1143 | 1154 | |
1144 | - map->unlock(map); | |
1155 | + map->unlock(map->lock_arg); | |
1145 | 1156 | |
1146 | 1157 | return ret; |
1147 | 1158 | } |
... | ... | @@ -1171,7 +1182,7 @@ |
1171 | 1182 | if (reg % map->reg_stride) |
1172 | 1183 | return -EINVAL; |
1173 | 1184 | |
1174 | - map->lock(map); | |
1185 | + map->lock(map->lock_arg); | |
1175 | 1186 | |
1176 | 1187 | if (regmap_volatile_range(map, reg, val_count) || map->cache_bypass || |
1177 | 1188 | map->cache_type == REGCACHE_NONE) { |
... | ... | @@ -1193,7 +1204,7 @@ |
1193 | 1204 | } |
1194 | 1205 | |
1195 | 1206 | out: |
1196 | - map->unlock(map); | |
1207 | + map->unlock(map->lock_arg); | |
1197 | 1208 | |
1198 | 1209 | return ret; |
1199 | 1210 | } |
1200 | 1211 | |
... | ... | @@ -1300,9 +1311,9 @@ |
1300 | 1311 | bool change; |
1301 | 1312 | int ret; |
1302 | 1313 | |
1303 | - map->lock(map); | |
1314 | + map->lock(map->lock_arg); | |
1304 | 1315 | ret = _regmap_update_bits(map, reg, mask, val, &change); |
1305 | - map->unlock(map); | |
1316 | + map->unlock(map->lock_arg); | |
1306 | 1317 | |
1307 | 1318 | return ret; |
1308 | 1319 | } |
1309 | 1320 | |
... | ... | @@ -1326,9 +1337,9 @@ |
1326 | 1337 | { |
1327 | 1338 | int ret; |
1328 | 1339 | |
1329 | - map->lock(map); | |
1340 | + map->lock(map->lock_arg); | |
1330 | 1341 | ret = _regmap_update_bits(map, reg, mask, val, change); |
1331 | - map->unlock(map); | |
1342 | + map->unlock(map->lock_arg); | |
1332 | 1343 | return ret; |
1333 | 1344 | } |
1334 | 1345 | EXPORT_SYMBOL_GPL(regmap_update_bits_check); |
... | ... | @@ -1357,7 +1368,7 @@ |
1357 | 1368 | if (map->patch) |
1358 | 1369 | return -EBUSY; |
1359 | 1370 | |
1360 | - map->lock(map); | |
1371 | + map->lock(map->lock_arg); | |
1361 | 1372 | |
1362 | 1373 | bypass = map->cache_bypass; |
1363 | 1374 | |
... | ... | @@ -1385,7 +1396,7 @@ |
1385 | 1396 | out: |
1386 | 1397 | map->cache_bypass = bypass; |
1387 | 1398 | |
1388 | - map->unlock(map); | |
1399 | + map->unlock(map->lock_arg); | |
1389 | 1400 | |
1390 | 1401 | return ret; |
1391 | 1402 | } |
include/linux/regmap.h
... | ... | @@ -53,6 +53,9 @@ |
53 | 53 | REGMAP_ENDIAN_NATIVE, |
54 | 54 | }; |
55 | 55 | |
56 | +typedef void (*regmap_lock)(void *); | |
57 | +typedef void (*regmap_unlock)(void *); | |
58 | + | |
56 | 59 | /** |
57 | 60 | * Configuration for the register map of a device. |
58 | 61 | * |
... | ... | @@ -75,6 +78,12 @@ |
75 | 78 | * @precious_reg: Optional callback returning true if the rgister |
76 | 79 | * should not be read outside of a call from the driver |
77 | 80 | * (eg, a clear on read interrupt status register). |
81 | + * @lock: Optional lock callback (overrides regmap's default lock | |
82 | + * function, based on spinlock or mutex). | |
83 | + * @unlock: As above for unlocking. | |
84 | + * @lock_arg: this field is passed as the only argument of lock/unlock | |
85 | + * functions (ignored in case regular lock/unlock functions | |
86 | + * are not overridden). | |
78 | 87 | * |
79 | 88 | * @max_register: Optional, specifies the maximum valid register index. |
80 | 89 | * @reg_defaults: Power on reset values for registers (for use with |
... | ... | @@ -116,6 +125,9 @@ |
116 | 125 | bool (*readable_reg)(struct device *dev, unsigned int reg); |
117 | 126 | bool (*volatile_reg)(struct device *dev, unsigned int reg); |
118 | 127 | bool (*precious_reg)(struct device *dev, unsigned int reg); |
128 | + regmap_lock lock; | |
129 | + regmap_unlock unlock; | |
130 | + void *lock_arg; | |
119 | 131 | |
120 | 132 | unsigned int max_register; |
121 | 133 | const struct reg_default *reg_defaults; |
... | ... | @@ -181,7 +193,9 @@ |
181 | 193 | * Description of a hardware bus for the register map infrastructure. |
182 | 194 | * |
183 | 195 | * @fast_io: Register IO is fast. Use a spinlock instead of a mutex |
184 | - * to perform locking. | |
196 | + * to perform locking. This field is ignored if custom lock/unlock | |
197 | + * functions are used (see fields lock/unlock of | |
198 | + * struct regmap_config). | |
185 | 199 | * @write: Write operation. |
186 | 200 | * @gather_write: Write operation with split register/value, return -ENOTSUPP |
187 | 201 | * if not implemented on a given device. |