Merge remote-tracking branch 'regmap/topic/drivers' into regmap-next
[firefly-linux-kernel-4.4.55.git] / drivers / base / regmap / regmap.c
index 58f84c3a6fc1031261f9d78cbdd9ee5101a096e5..e3ee9cabccb46d9ff31d2954715308c08007aedd 100644 (file)
@@ -374,6 +374,9 @@ int regmap_reinit_cache(struct regmap *map, const struct regmap_config *config)
 
        regmap_debugfs_init(map);
 
+       map->cache_bypass = false;
+       map->cache_only = false;
+
        ret = regcache_init(map, config);
 
        mutex_unlock(&map->lock);
@@ -783,6 +786,64 @@ int regmap_update_bits_check(struct regmap *map, unsigned int reg,
 }
 EXPORT_SYMBOL_GPL(regmap_update_bits_check);
 
+/**
+ * regmap_register_patch: Register and apply register updates to be applied
+ *                        on device initialistion
+ *
+ * @map: Register map to apply updates to.
+ * @regs: Values to update.
+ * @num_regs: Number of entries in regs.
+ *
+ * Register a set of register updates to be applied to the device
+ * whenever the device registers are synchronised with the cache and
+ * apply them immediately.  Typically this is used to apply
+ * corrections to be applied to the device defaults on startup, such
+ * as the updates some vendors provide to undocumented registers.
+ */
+int regmap_register_patch(struct regmap *map, const struct reg_default *regs,
+                         int num_regs)
+{
+       int i, ret;
+       bool bypass;
+
+       /* If needed the implementation can be extended to support this */
+       if (map->patch)
+               return -EBUSY;
+
+       mutex_lock(&map->lock);
+
+       bypass = map->cache_bypass;
+
+       map->cache_bypass = true;
+
+       /* Write out first; it's useful to apply even if we fail later. */
+       for (i = 0; i < num_regs; i++) {
+               ret = _regmap_write(map, regs[i].reg, regs[i].def);
+               if (ret != 0) {
+                       dev_err(map->dev, "Failed to write %x = %x: %d\n",
+                               regs[i].reg, regs[i].def, ret);
+                       goto out;
+               }
+       }
+
+       map->patch = kcalloc(num_regs, sizeof(struct reg_default), GFP_KERNEL);
+       if (map->patch != NULL) {
+               memcpy(map->patch, regs,
+                      num_regs * sizeof(struct reg_default));
+               map->patch_regs = num_regs;
+       } else {
+               ret = -ENOMEM;
+       }
+
+out:
+       map->cache_bypass = bypass;
+
+       mutex_unlock(&map->lock);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(regmap_register_patch);
+
 static int __init regmap_initcall(void)
 {
        regmap_debugfs_initcall();