diff options
Diffstat (limited to 'drivers/base/regmap')
-rw-r--r-- | drivers/base/regmap/internal.h | 3 | ||||
-rw-r--r-- | drivers/base/regmap/regcache.c | 11 | ||||
-rw-r--r-- | drivers/base/regmap/regmap.c | 73 |
3 files changed, 87 insertions, 0 deletions
diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h index 1a02b7537c8b..d141b80479b5 100644 --- a/drivers/base/regmap/internal.h +++ b/drivers/base/regmap/internal.h | |||
@@ -75,6 +75,9 @@ struct regmap { | |||
75 | const void *reg_defaults_raw; | 75 | const void *reg_defaults_raw; |
76 | void *cache; | 76 | void *cache; |
77 | bool cache_dirty; | 77 | bool cache_dirty; |
78 | |||
79 | struct reg_default *patch; | ||
80 | int patch_regs; | ||
78 | }; | 81 | }; |
79 | 82 | ||
80 | struct regcache_ops { | 83 | struct regcache_ops { |
diff --git a/drivers/base/regmap/regcache.c b/drivers/base/regmap/regcache.c index d1daa5e9fadf..5cd2a37e7688 100644 --- a/drivers/base/regmap/regcache.c +++ b/drivers/base/regmap/regcache.c | |||
@@ -268,6 +268,17 @@ int regcache_sync(struct regmap *map) | |||
268 | map->cache_ops->name); | 268 | map->cache_ops->name); |
269 | name = map->cache_ops->name; | 269 | name = map->cache_ops->name; |
270 | trace_regcache_sync(map->dev, name, "start"); | 270 | trace_regcache_sync(map->dev, name, "start"); |
271 | |||
272 | /* Apply any patch first */ | ||
273 | for (i = 0; i < map->patch_regs; i++) { | ||
274 | ret = _regmap_write(map, map->patch[i].reg, map->patch[i].def); | ||
275 | if (ret != 0) { | ||
276 | dev_err(map->dev, "Failed to write %x = %x: %d\n", | ||
277 | map->patch[i].reg, map->patch[i].def, ret); | ||
278 | goto out; | ||
279 | } | ||
280 | } | ||
281 | |||
271 | if (!map->cache_dirty) | 282 | if (!map->cache_dirty) |
272 | goto out; | 283 | goto out; |
273 | if (map->cache_ops->sync) { | 284 | if (map->cache_ops->sync) { |
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 65558034318f..7ac234f0b1c5 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c | |||
@@ -672,6 +672,79 @@ int regmap_update_bits_check(struct regmap *map, unsigned int reg, | |||
672 | } | 672 | } |
673 | EXPORT_SYMBOL_GPL(regmap_update_bits_check); | 673 | EXPORT_SYMBOL_GPL(regmap_update_bits_check); |
674 | 674 | ||
675 | /** | ||
676 | * regmap_register_patch: Register and apply register updates to be applied | ||
677 | * on device initialistion | ||
678 | * | ||
679 | * @map: Register map to apply updates to. | ||
680 | * @regs: Values to update. | ||
681 | * @num_regs: Number of entries in regs. | ||
682 | * | ||
683 | * Register a set of register updates to be applied to the device | ||
684 | * whenever the device registers are synchronised with the cache and | ||
685 | * apply them immediately. Typically this is used to apply | ||
686 | * corrections to be applied to the device defaults on startup, such | ||
687 | * as the updates some vendors provide to undocumented registers. | ||
688 | */ | ||
689 | int regmap_register_patch(struct regmap *map, const struct reg_default *regs, | ||
690 | int num_regs) | ||
691 | { | ||
692 | int i, ret; | ||
693 | bool bypass; | ||
694 | |||
695 | /* If needed the implementation can be extended to support this */ | ||
696 | if (map->patch) | ||
697 | return -EBUSY; | ||
698 | |||
699 | mutex_lock(&map->lock); | ||
700 | |||
701 | bypass = map->cache_bypass; | ||
702 | |||
703 | map->cache_bypass = true; | ||
704 | |||
705 | /* Write out first; it's useful to apply even if we fail later. */ | ||
706 | for (i = 0; i < num_regs; i++) { | ||
707 | ret = _regmap_write(map, regs[i].reg, regs[i].def); | ||
708 | if (ret != 0) { | ||
709 | dev_err(map->dev, "Failed to write %x = %x: %d\n", | ||
710 | regs[i].reg, regs[i].def, ret); | ||
711 | goto out; | ||
712 | } | ||
713 | } | ||
714 | |||
715 | map->patch = kcalloc(sizeof(struct reg_default), num_regs, GFP_KERNEL); | ||
716 | if (map->patch != NULL) { | ||
717 | memcpy(map->patch, regs, | ||
718 | num_regs * sizeof(struct reg_default)); | ||
719 | map->patch_regs = num_regs; | ||
720 | } else { | ||
721 | ret = -ENOMEM; | ||
722 | } | ||
723 | |||
724 | out: | ||
725 | map->cache_bypass = bypass; | ||
726 | |||
727 | mutex_unlock(&map->lock); | ||
728 | |||
729 | return ret; | ||
730 | } | ||
731 | EXPORT_SYMBOL_GPL(regmap_register_patch); | ||
732 | |||
733 | /* | ||
734 | * regmap_get_val_bytes(): Report the size of a register value | ||
735 | * | ||
736 | * Report the size of a register value, mainly intended to for use by | ||
737 | * generic infrastructure built on top of regmap. | ||
738 | */ | ||
739 | int regmap_get_val_bytes(struct regmap *map) | ||
740 | { | ||
741 | if (map->format.format_write) | ||
742 | return -EINVAL; | ||
743 | |||
744 | return map->format.val_bytes; | ||
745 | } | ||
746 | EXPORT_SYMBOL_GPL(regmap_get_val_bytes); | ||
747 | |||
675 | static int __init regmap_initcall(void) | 748 | static int __init regmap_initcall(void) |
676 | { | 749 | { |
677 | regmap_debugfs_initcall(); | 750 | regmap_debugfs_initcall(); |