summaryrefslogtreecommitdiff
path: root/drivers/base/regmap/regcache.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/base/regmap/regcache.c')
-rw-r--r--drivers/base/regmap/regcache.c54
1 files changed, 53 insertions, 1 deletions
diff --git a/drivers/base/regmap/regcache.c b/drivers/base/regmap/regcache.c
index 4c07802986b2..673938f972a8 100644
--- a/drivers/base/regmap/regcache.c
+++ b/drivers/base/regmap/regcache.c
@@ -682,6 +682,53 @@ static int regcache_sync_block_raw_flush(struct regmap *map, const void **data,
return ret;
}
+static int regcache_sync_block_raw_multi_reg(struct regmap *map, void *block,
+ unsigned long *cache_present,
+ unsigned int block_base,
+ unsigned int start,
+ unsigned int end)
+{
+ unsigned int i, val;
+ unsigned int regtmp = 0;
+ int ret = 0;
+ struct reg_sequence *regs;
+ size_t num_regs = ((end - start) + 1);
+
+ regs = kcalloc(num_regs, sizeof(struct reg_default), GFP_KERNEL);
+ if (!regs)
+ return -ENOMEM;
+
+ num_regs = 0;
+ for (i = start; i < end; i++) {
+ regtmp = block_base + (i * map->reg_stride);
+
+ /* skip registers that are not defined/available */
+ if (!regcache_reg_present(cache_present, i))
+ continue;
+
+ val = regcache_get_val(map, block, i);
+
+ /* Is this the hardware default? If so skip. */
+ ret = regcache_lookup_reg(map, regtmp);
+ if (ret >= 0 && val == map->reg_defaults[ret].def) {
+ continue;
+ } else {
+ regs[num_regs].reg = regtmp;
+ regs[num_regs].def = val;
+ regs[num_regs].delay_us = 0;
+ num_regs += 1;
+ }
+ }
+ ret = 0;
+ if (num_regs) {
+ dev_dbg(map->dev, "%s: start: 0x%x - end: 0x%x\n",
+ __func__, regs[0].reg, regs[num_regs-1].reg);
+ ret = _regmap_raw_multi_reg_write(map, regs, num_regs);
+ }
+ kfree(regs);
+ return ret;
+}
+
static int regcache_sync_block_raw(struct regmap *map, void *block,
unsigned long *cache_present,
unsigned int block_base, unsigned int start,
@@ -729,7 +776,12 @@ int regcache_sync_block(struct regmap *map, void *block,
unsigned int block_base, unsigned int start,
unsigned int end)
{
- if (regmap_can_raw_write(map) && !map->use_single_write)
+ if (regmap_can_raw_write(map) && map->can_multi_write)
+ return regcache_sync_block_raw_multi_reg(map, block,
+ cache_present,
+ block_base, start,
+ end);
+ else if (regmap_can_raw_write(map) && !map->use_single_write)
return regcache_sync_block_raw(map, block, cache_present,
block_base, start, end);
else