diff options
Diffstat (limited to 'drivers/base/regmap/regcache.c')
-rw-r--r-- | drivers/base/regmap/regcache.c | 54 |
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 |