Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

regmap: cache: Write consecutive registers in a single block write

When syncing blocks of data using raw writes combine the writes into a
single block write, saving us bus overhead for setup, addressing and
teardown.

Currently the block write is done unconditionally as it is expected that
hardware which has a register format which can support raw writes will
support auto incrementing writes, this decision may need to be revised in
future.

Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Reviewed-by: Dimitris Papastamos <dp@opensource.wolfsonmicro.com>

+47 -17
+47 -17
drivers/base/regmap/regcache.c
··· 579 579 return 0; 580 580 } 581 581 582 + static int regcache_sync_block_raw_flush(struct regmap *map, const void **data, 583 + unsigned int base, unsigned int cur) 584 + { 585 + size_t val_bytes = map->format.val_bytes; 586 + int ret, count; 587 + 588 + if (*data == NULL) 589 + return 0; 590 + 591 + count = cur - base; 592 + 593 + dev_dbg(map->dev, "Writing %d bytes for %d registers from 0x%x-0x%x\n", 594 + count * val_bytes, count, base, cur - 1); 595 + 596 + map->cache_bypass = 1; 597 + 598 + ret = _regmap_raw_write(map, base, *data, count * val_bytes, 599 + false); 600 + 601 + map->cache_bypass = 0; 602 + 603 + *data = NULL; 604 + 605 + return ret; 606 + } 607 + 582 608 int regcache_sync_block_raw(struct regmap *map, void *block, 583 609 unsigned int block_base, unsigned int start, 584 610 unsigned int end) 585 611 { 586 - unsigned int i, regtmp, val; 587 - const void *addr; 612 + unsigned int i, val; 613 + unsigned int regtmp = 0; 614 + unsigned int base = 0; 615 + const void *data = NULL; 588 616 int ret; 589 617 590 618 for (i = start; i < end; i++) { 591 619 regtmp = block_base + (i * map->reg_stride); 592 620 593 - if (!regcache_reg_present(map, regtmp)) 621 + if (!regcache_reg_present(map, regtmp)) { 622 + ret = regcache_sync_block_raw_flush(map, &data, 623 + base, regtmp); 624 + if (ret != 0) 625 + return ret; 594 626 continue; 627 + } 595 628 596 629 val = regcache_get_val(map, block, i); 597 630 598 631 /* Is this the hardware default? If so skip. */ 599 632 ret = regcache_lookup_reg(map, regtmp); 600 - if (ret >= 0 && val == map->reg_defaults[ret].def) 633 + if (ret >= 0 && val == map->reg_defaults[ret].def) { 634 + ret = regcache_sync_block_raw_flush(map, &data, 635 + base, regtmp); 636 + if (ret != 0) 637 + return ret; 601 638 continue; 639 + } 602 640 603 - map->cache_bypass = 1; 604 - 605 - addr = regcache_get_val_addr(map, block, i); 606 - ret = _regmap_raw_write(map, regtmp, addr, 607 - map->format.val_bytes, 608 - false); 609 - 610 - map->cache_bypass = 0; 611 - if (ret != 0) 612 - return ret; 613 - dev_dbg(map->dev, "Synced register %#x, value %#x\n", 614 - regtmp, val); 641 + if (!data) { 642 + data = regcache_get_val_addr(map, block, i); 643 + base = regtmp; 644 + } 615 645 } 616 646 617 - return 0; 647 + return regcache_sync_block_raw_flush(map, &data, base, regtmp); 618 648 } 619 649 620 650 int regcache_sync_block(struct regmap *map, void *block,