diff options
author | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2012-02-20 16:21:33 -0500 |
---|---|---|
committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2012-02-20 16:21:33 -0500 |
commit | aca1e172a1096ed3785e0da01d82943b7562527c (patch) | |
tree | 0826c140b4e31acd7f8546727498dd849f099ba6 /drivers/base/regmap | |
parent | 3bf06a1ad9b147ca3a64b119d70c4a7c0ace3695 (diff) | |
parent | 2a14d7d9b7439fe62082a60a7f8983ccb463d134 (diff) |
Merge branch 'topic/patch' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap into regmap-drivers
Diffstat (limited to 'drivers/base/regmap')
-rw-r--r-- | drivers/base/regmap/internal.h | 3 | ||||
-rw-r--r-- | drivers/base/regmap/regcache.c | 14 | ||||
-rw-r--r-- | drivers/base/regmap/regmap.c | 58 |
3 files changed, 75 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..e9032c329067 100644 --- a/drivers/base/regmap/regcache.c +++ b/drivers/base/regmap/regcache.c | |||
@@ -268,8 +268,22 @@ 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 | |||
271 | if (!map->cache_dirty) | 272 | if (!map->cache_dirty) |
272 | goto out; | 273 | goto out; |
274 | |||
275 | /* Apply any patch first */ | ||
276 | map->cache_bypass = 1; | ||
277 | for (i = 0; i < map->patch_regs; i++) { | ||
278 | ret = _regmap_write(map, map->patch[i].reg, map->patch[i].def); | ||
279 | if (ret != 0) { | ||
280 | dev_err(map->dev, "Failed to write %x = %x: %d\n", | ||
281 | map->patch[i].reg, map->patch[i].def, ret); | ||
282 | goto out; | ||
283 | } | ||
284 | } | ||
285 | map->cache_bypass = 0; | ||
286 | |||
273 | if (map->cache_ops->sync) { | 287 | if (map->cache_ops->sync) { |
274 | ret = map->cache_ops->sync(map); | 288 | ret = map->cache_ops->sync(map); |
275 | } else { | 289 | } else { |
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 677aeab24f75..1752f13ddebc 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c | |||
@@ -711,6 +711,64 @@ int regmap_update_bits_check(struct regmap *map, unsigned int reg, | |||
711 | } | 711 | } |
712 | EXPORT_SYMBOL_GPL(regmap_update_bits_check); | 712 | EXPORT_SYMBOL_GPL(regmap_update_bits_check); |
713 | 713 | ||
714 | /** | ||
715 | * regmap_register_patch: Register and apply register updates to be applied | ||
716 | * on device initialistion | ||
717 | * | ||
718 | * @map: Register map to apply updates to. | ||
719 | * @regs: Values to update. | ||
720 | * @num_regs: Number of entries in regs. | ||
721 | * | ||
722 | * Register a set of register updates to be applied to the device | ||
723 | * whenever the device registers are synchronised with the cache and | ||
724 | * apply them immediately. Typically this is used to apply | ||
725 | * corrections to be applied to the device defaults on startup, such | ||
726 | * as the updates some vendors provide to undocumented registers. | ||
727 | */ | ||
728 | int regmap_register_patch(struct regmap *map, const struct reg_default *regs, | ||
729 | int num_regs) | ||
730 | { | ||
731 | int i, ret; | ||
732 | bool bypass; | ||
733 | |||
734 | /* If needed the implementation can be extended to support this */ | ||
735 | if (map->patch) | ||
736 | return -EBUSY; | ||
737 | |||
738 | mutex_lock(&map->lock); | ||
739 | |||
740 | bypass = map->cache_bypass; | ||
741 | |||
742 | map->cache_bypass = true; | ||
743 | |||
744 | /* Write out first; it's useful to apply even if we fail later. */ | ||
745 | for (i = 0; i < num_regs; i++) { | ||
746 | ret = _regmap_write(map, regs[i].reg, regs[i].def); | ||
747 | if (ret != 0) { | ||
748 | dev_err(map->dev, "Failed to write %x = %x: %d\n", | ||
749 | regs[i].reg, regs[i].def, ret); | ||
750 | goto out; | ||
751 | } | ||
752 | } | ||
753 | |||
754 | map->patch = kcalloc(num_regs, sizeof(struct reg_default), GFP_KERNEL); | ||
755 | if (map->patch != NULL) { | ||
756 | memcpy(map->patch, regs, | ||
757 | num_regs * sizeof(struct reg_default)); | ||
758 | map->patch_regs = num_regs; | ||
759 | } else { | ||
760 | ret = -ENOMEM; | ||
761 | } | ||
762 | |||
763 | out: | ||
764 | map->cache_bypass = bypass; | ||
765 | |||
766 | mutex_unlock(&map->lock); | ||
767 | |||
768 | return ret; | ||
769 | } | ||
770 | EXPORT_SYMBOL_GPL(regmap_register_patch); | ||
771 | |||
714 | static int __init regmap_initcall(void) | 772 | static int __init regmap_initcall(void) |
715 | { | 773 | { |
716 | regmap_debugfs_initcall(); | 774 | regmap_debugfs_initcall(); |