summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/base/regmap/internal.h11
-rw-r--r--drivers/base/regmap/regmap.c182
2 files changed, 70 insertions, 123 deletions
diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h
index a6e4689000af..0a17fe3e8cf4 100644
--- a/drivers/base/regmap/internal.h
+++ b/drivers/base/regmap/internal.h
@@ -10,6 +10,7 @@
#ifndef _REGMAP_INTERNAL_H
#define _REGMAP_INTERNAL_H
+#include <linux/cleanup.h>
#include <linux/device.h>
#include <linux/regmap.h>
#include <linux/fs.h>
@@ -185,6 +186,16 @@ struct regmap {
struct hwspinlock *hwlock;
};
+/*
+ * Scoped guard for the regmap lock. The lock/unlock callbacks are selected
+ * at init time (mutex, spinlock, raw spinlock, hwspinlock or none) and never
+ * fail, so an unconditional guard is sufficient. Use with guard(regmap)(map)
+ * or scoped_guard(regmap, map) { ... }.
+ */
+DEFINE_GUARD(regmap, struct regmap *,
+ _T->lock(_T->lock_arg),
+ _T->unlock(_T->lock_arg))
+
struct regcache_ops {
const char *name;
enum regcache_type type;
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
index e6e022b02637..f3a269f32297 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -115,9 +115,8 @@ bool regmap_cached(struct regmap *map, unsigned int reg)
if (map->max_register_is_set && reg > map->max_register)
return false;
- map->lock(map->lock_arg);
- ret = regcache_read(map, reg, &val);
- map->unlock(map->lock_arg);
+ scoped_guard(regmap, map)
+ ret = regcache_read(map, reg, &val);
if (ret)
return false;
@@ -1977,18 +1976,12 @@ int _regmap_write(struct regmap *map, unsigned int reg,
*/
int regmap_write(struct regmap *map, unsigned int reg, unsigned int val)
{
- int ret;
-
if (!IS_ALIGNED(reg, map->reg_stride))
return -EINVAL;
- map->lock(map->lock_arg);
-
- ret = _regmap_write(map, reg, val);
-
- map->unlock(map->lock_arg);
+ guard(regmap)(map);
- return ret;
+ return _regmap_write(map, reg, val);
}
EXPORT_SYMBOL_GPL(regmap_write);
@@ -2009,7 +2002,7 @@ int regmap_write_async(struct regmap *map, unsigned int reg, unsigned int val)
if (!IS_ALIGNED(reg, map->reg_stride))
return -EINVAL;
- map->lock(map->lock_arg);
+ guard(regmap)(map);
map->async = true;
@@ -2017,8 +2010,6 @@ int regmap_write_async(struct regmap *map, unsigned int reg, unsigned int val)
map->async = false;
- map->unlock(map->lock_arg);
-
return ret;
}
EXPORT_SYMBOL_GPL(regmap_write_async);
@@ -2080,20 +2071,14 @@ int _regmap_raw_write(struct regmap *map, unsigned int reg,
int regmap_raw_write(struct regmap *map, unsigned int reg,
const void *val, size_t val_len)
{
- int ret;
-
if (!regmap_can_raw_write(map))
return -EINVAL;
if (val_len % map->format.val_bytes)
return -EINVAL;
- map->lock(map->lock_arg);
+ guard(regmap)(map);
- ret = _regmap_raw_write(map, reg, val, val_len, false);
-
- map->unlock(map->lock_arg);
-
- return ret;
+ return _regmap_raw_write(map, reg, val, val_len, false);
}
EXPORT_SYMBOL_GPL(regmap_raw_write);
@@ -2211,21 +2196,17 @@ int regmap_noinc_write(struct regmap *map, unsigned int reg,
if (val_len == 0)
return -EINVAL;
- map->lock(map->lock_arg);
+ guard(regmap)(map);
- if (!regmap_volatile(map, reg) || !regmap_writeable_noinc(map, reg)) {
- ret = -EINVAL;
- goto out_unlock;
- }
+ if (!regmap_volatile(map, reg) || !regmap_writeable_noinc(map, reg))
+ return -EINVAL;
/*
* Use the accelerated operation if we can. The val drops the const
* typing in order to facilitate code reuse in regmap_noinc_readwrite().
*/
- if (map->bus->reg_noinc_write) {
- ret = regmap_noinc_readwrite(map, reg, (void *)val, val_len, true);
- goto out_unlock;
- }
+ if (map->bus->reg_noinc_write)
+ return regmap_noinc_readwrite(map, reg, (void *)val, val_len, true);
while (val_len) {
if (map->max_raw_write && map->max_raw_write < val_len)
@@ -2234,14 +2215,12 @@ int regmap_noinc_write(struct regmap *map, unsigned int reg,
write_len = val_len;
ret = _regmap_raw_write(map, reg, val, write_len, true);
if (ret)
- goto out_unlock;
+ return ret;
val = ((u8 *)val) + write_len;
val_len -= write_len;
}
-out_unlock:
- map->unlock(map->lock_arg);
- return ret;
+ return 0;
}
EXPORT_SYMBOL_GPL(regmap_noinc_write);
@@ -2357,7 +2336,8 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val,
* single write operations.
*/
if (!map->write || !map->format.parse_inplace) {
- map->lock(map->lock_arg);
+ guard(regmap)(map);
+
for (i = 0; i < val_count; i++) {
unsigned int ival;
@@ -2372,18 +2352,15 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val,
ival = *(u32 *)(val + (i * val_bytes));
break;
default:
- ret = -EINVAL;
- goto out;
+ return -EINVAL;
}
ret = _regmap_write(map,
reg + regmap_get_offset(map, i),
ival);
if (ret != 0)
- goto out;
+ return ret;
}
-out:
- map->unlock(map->lock_arg);
} else {
void *wval;
@@ -2653,15 +2630,9 @@ static int _regmap_multi_reg_write(struct regmap *map,
int regmap_multi_reg_write(struct regmap *map, const struct reg_sequence *regs,
int num_regs)
{
- int ret;
-
- map->lock(map->lock_arg);
-
- ret = _regmap_multi_reg_write(map, regs, num_regs);
-
- map->unlock(map->lock_arg);
+ guard(regmap)(map);
- return ret;
+ return _regmap_multi_reg_write(map, regs, num_regs);
}
EXPORT_SYMBOL_GPL(regmap_multi_reg_write);
@@ -2690,7 +2661,7 @@ int regmap_multi_reg_write_bypassed(struct regmap *map,
int ret;
bool bypass;
- map->lock(map->lock_arg);
+ guard(regmap)(map);
bypass = map->cache_bypass;
map->cache_bypass = true;
@@ -2699,8 +2670,6 @@ int regmap_multi_reg_write_bypassed(struct regmap *map,
map->cache_bypass = bypass;
- map->unlock(map->lock_arg);
-
return ret;
}
EXPORT_SYMBOL_GPL(regmap_multi_reg_write_bypassed);
@@ -2737,7 +2706,7 @@ int regmap_raw_write_async(struct regmap *map, unsigned int reg,
if (!IS_ALIGNED(reg, map->reg_stride))
return -EINVAL;
- map->lock(map->lock_arg);
+ guard(regmap)(map);
map->async = true;
@@ -2745,8 +2714,6 @@ int regmap_raw_write_async(struct regmap *map, unsigned int reg,
map->async = false;
- map->unlock(map->lock_arg);
-
return ret;
}
EXPORT_SYMBOL_GPL(regmap_raw_write_async);
@@ -2863,18 +2830,12 @@ static int _regmap_read(struct regmap *map, unsigned int reg,
*/
int regmap_read(struct regmap *map, unsigned int reg, unsigned int *val)
{
- int ret;
-
if (!IS_ALIGNED(reg, map->reg_stride))
return -EINVAL;
- map->lock(map->lock_arg);
+ guard(regmap)(map);
- ret = _regmap_read(map, reg, val);
-
- map->unlock(map->lock_arg);
-
- return ret;
+ return _regmap_read(map, reg, val);
}
EXPORT_SYMBOL_GPL(regmap_read);
@@ -2897,7 +2858,7 @@ int regmap_read_bypassed(struct regmap *map, unsigned int reg, unsigned int *val
if (!IS_ALIGNED(reg, map->reg_stride))
return -EINVAL;
- map->lock(map->lock_arg);
+ guard(regmap)(map);
bypass = map->cache_bypass;
cache_only = map->cache_only;
@@ -2909,8 +2870,6 @@ int regmap_read_bypassed(struct regmap *map, unsigned int reg, unsigned int *val
map->cache_bypass = bypass;
map->cache_only = cache_only;
- map->unlock(map->lock_arg);
-
return ret;
}
EXPORT_SYMBOL_GPL(regmap_read_bypassed);
@@ -2941,22 +2900,18 @@ int regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
if (val_count == 0)
return -EINVAL;
- map->lock(map->lock_arg);
+ guard(regmap)(map);
if (regmap_volatile_range(map, reg, val_count) || map->cache_bypass ||
map->cache_type == REGCACHE_NONE) {
size_t chunk_count, chunk_bytes;
size_t chunk_regs = val_count;
- if (!map->cache_bypass && map->cache_only) {
- ret = -EBUSY;
- goto out;
- }
+ if (!map->cache_bypass && map->cache_only)
+ return -EBUSY;
- if (!map->read) {
- ret = -ENOTSUPP;
- goto out;
- }
+ if (!map->read)
+ return -ENOTSUPP;
if (map->use_single_read)
chunk_regs = 1;
@@ -2970,7 +2925,7 @@ int regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
for (i = 0; i < chunk_count; i++) {
ret = _regmap_raw_read(map, reg, val, chunk_bytes, false);
if (ret != 0)
- goto out;
+ return ret;
reg += regmap_get_offset(map, chunk_regs);
val += chunk_bytes;
@@ -2981,7 +2936,7 @@ int regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
if (val_len) {
ret = _regmap_raw_read(map, reg, val, val_len, false);
if (ret != 0)
- goto out;
+ return ret;
}
} else {
/* Otherwise go word by word for the cache; should be low
@@ -2991,16 +2946,13 @@ int regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
ret = _regmap_read(map, reg + regmap_get_offset(map, i),
&v);
if (ret != 0)
- goto out;
+ return ret;
map->format.format_val(val + (i * val_bytes), v, 0);
}
}
- out:
- map->unlock(map->lock_arg);
-
- return ret;
+ return 0;
}
EXPORT_SYMBOL_GPL(regmap_raw_read);
@@ -3041,12 +2993,10 @@ int regmap_noinc_read(struct regmap *map, unsigned int reg,
if (val_len == 0)
return -EINVAL;
- map->lock(map->lock_arg);
+ guard(regmap)(map);
- if (!regmap_volatile(map, reg) || !regmap_readable_noinc(map, reg)) {
- ret = -EINVAL;
- goto out_unlock;
- }
+ if (!regmap_volatile(map, reg) || !regmap_readable_noinc(map, reg))
+ return -EINVAL;
/*
* We have not defined the FIFO semantics for cache, as the
@@ -3054,16 +3004,12 @@ int regmap_noinc_read(struct regmap *map, unsigned int reg,
* written value? Just avoid this by always reading the FIFO
* even when using cache. Cache only will not work.
*/
- if (!map->cache_bypass && map->cache_only) {
- ret = -EBUSY;
- goto out_unlock;
- }
+ if (!map->cache_bypass && map->cache_only)
+ return -EBUSY;
/* Use the accelerated operation if we can */
- if (map->bus->reg_noinc_read) {
- ret = regmap_noinc_readwrite(map, reg, val, val_len, false);
- goto out_unlock;
- }
+ if (map->bus->reg_noinc_read)
+ return regmap_noinc_readwrite(map, reg, val, val_len, false);
while (val_len) {
if (map->max_raw_read && map->max_raw_read < val_len)
@@ -3072,14 +3018,12 @@ int regmap_noinc_read(struct regmap *map, unsigned int reg,
read_len = val_len;
ret = _regmap_raw_read(map, reg, val, read_len, true);
if (ret)
- goto out_unlock;
+ return ret;
val = ((u8 *)val) + read_len;
val_len -= read_len;
}
-out_unlock:
- map->unlock(map->lock_arg);
- return ret;
+ return 0;
}
EXPORT_SYMBOL_GPL(regmap_noinc_read);
@@ -3149,22 +3093,20 @@ static int _regmap_bulk_read(struct regmap *map, unsigned int reg,
u8 *u8 = val;
int ret, i;
- map->lock(map->lock_arg);
+ guard(regmap)(map);
for (i = 0; i < val_count; i++) {
unsigned int ival;
if (regs) {
- if (!IS_ALIGNED(regs[i], map->reg_stride)) {
- ret = -EINVAL;
- goto out;
- }
+ if (!IS_ALIGNED(regs[i], map->reg_stride))
+ return -EINVAL;
ret = _regmap_read(map, regs[i], &ival);
} else {
ret = _regmap_read(map, reg + regmap_get_offset(map, i), &ival);
}
if (ret != 0)
- goto out;
+ return ret;
switch (map->format.val_bytes) {
case 4:
@@ -3177,13 +3119,11 @@ static int _regmap_bulk_read(struct regmap *map, unsigned int reg,
u8[i] = ival;
break;
default:
- ret = -EINVAL;
- goto out;
+ return -EINVAL;
}
}
-out:
- map->unlock(map->lock_arg);
- return ret;
+
+ return 0;
}
/**
@@ -3310,7 +3250,7 @@ int regmap_update_bits_base(struct regmap *map, unsigned int reg,
{
int ret;
- map->lock(map->lock_arg);
+ guard(regmap)(map);
map->async = async;
@@ -3318,8 +3258,6 @@ int regmap_update_bits_base(struct regmap *map, unsigned int reg,
map->async = false;
- map->unlock(map->lock_arg);
-
return ret;
}
EXPORT_SYMBOL_GPL(regmap_update_bits_base);
@@ -3452,19 +3390,17 @@ int regmap_register_patch(struct regmap *map, const struct reg_sequence *regs,
return -ENOMEM;
}
- map->lock(map->lock_arg);
+ scoped_guard(regmap, map) {
+ bypass = map->cache_bypass;
- bypass = map->cache_bypass;
+ map->cache_bypass = true;
+ map->async = true;
- map->cache_bypass = true;
- map->async = true;
-
- ret = _regmap_multi_reg_write(map, regs, num_regs);
+ ret = _regmap_multi_reg_write(map, regs, num_regs);
- map->async = false;
- map->cache_bypass = bypass;
-
- map->unlock(map->lock_arg);
+ map->async = false;
+ map->cache_bypass = bypass;
+ }
regmap_async_complete(map);