aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base
diff options
context:
space:
mode:
authorMark Brown <broonie@opensource.wolfsonmicro.com>2012-01-21 07:01:14 -0500
committerMark Brown <broonie@opensource.wolfsonmicro.com>2012-01-23 09:01:18 -0500
commit22f0d90a34827812413bb3fbeda6a2a79bb58423 (patch)
treec54935a6e2637408da23aa261c81f89dffa0724e /drivers/base
parentdcd6c92267155e70a94b3927bce681ce74b80d1f (diff)
regmap: Support register patch sets
Device manufacturers frequently provide register sequences, usually not fully documented, to be run at startup in order to provide better defaults for devices (for example, improving performance in the light of silicon evaluation). Support such updates by allowing drivers to register update sets with the core. These updates will be written to the device immediately and will also be rewritten when the cache is synced. The assumption is that the reason for resyncing the cache will always be that the device has been powered off. If this turns out to not be the case then a separate operation can be provided. Currently the implementation only allows a single set of updates to be specified for a device, this could be extended in future. Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'drivers/base')
-rw-r--r--drivers/base/regmap/internal.h3
-rw-r--r--drivers/base/regmap/regcache.c11
-rw-r--r--drivers/base/regmap/regmap.c58
3 files changed, 72 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
80struct regcache_ops { 83struct regcache_ops {
diff --git a/drivers/base/regmap/regcache.c b/drivers/base/regmap/regcache.c
index 1ead66186b7c..ce2034c10ffb 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 be10a4ff6609..28e89fd7c28d 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -669,6 +669,64 @@ int regmap_update_bits_check(struct regmap *map, unsigned int reg,
669} 669}
670EXPORT_SYMBOL_GPL(regmap_update_bits_check); 670EXPORT_SYMBOL_GPL(regmap_update_bits_check);
671 671
672/**
673 * regmap_register_patch: Register and apply register updates to be applied
674 * on device initialistion
675 *
676 * @map: Register map to apply updates to.
677 * @regs: Values to update.
678 * @num_regs: Number of entries in regs.
679 *
680 * Register a set of register updates to be applied to the device
681 * whenever the device registers are synchronised with the cache and
682 * apply them immediately. Typically this is used to apply
683 * corrections to be applied to the device defaults on startup, such
684 * as the updates some vendors provide to undocumented registers.
685 */
686int regmap_register_patch(struct regmap *map, const struct reg_default *regs,
687 int num_regs)
688{
689 int i, ret;
690 bool bypass;
691
692 /* If needed the implementation can be extended to support this */
693 if (map->patch)
694 return -EBUSY;
695
696 mutex_lock(&map->lock);
697
698 bypass = map->cache_bypass;
699
700 map->cache_bypass = true;
701
702 /* Write out first; it's useful to apply even if we fail later. */
703 for (i = 0; i < num_regs; i++) {
704 ret = _regmap_write(map, regs[i].reg, regs[i].def);
705 if (ret != 0) {
706 dev_err(map->dev, "Failed to write %x = %x: %d\n",
707 regs[i].reg, regs[i].def, ret);
708 goto out;
709 }
710 }
711
712 map->patch = kcalloc(sizeof(struct reg_default), num_regs, GFP_KERNEL);
713 if (map->patch != NULL) {
714 memcpy(map->patch, regs,
715 num_regs * sizeof(struct reg_default));
716 map->patch_regs = num_regs;
717 } else {
718 ret = -ENOMEM;
719 }
720
721out:
722 map->cache_bypass = bypass;
723
724 mutex_unlock(&map->lock);
725
726 return ret;
727}
728EXPORT_SYMBOL_GPL(regmap_register_patch);
729
672static int __init regmap_initcall(void) 730static int __init regmap_initcall(void)
673{ 731{
674 regmap_debugfs_initcall(); 732 regmap_debugfs_initcall();