regmap: Track if the register cache is dirty and suppress unneeded syncs
authorMark Brown <broonie@opensource.wolfsonmicro.com>
Wed, 26 Oct 2011 08:34:22 +0000 (10:34 +0200)
committerMark Brown <broonie@opensource.wolfsonmicro.com>
Tue, 8 Nov 2011 11:38:15 +0000 (11:38 +0000)
Allow drivers to optimise out the register cache sync if they didn't need
to do one. If the hardware is desynced from the register cache (by power
loss for example) then the driver should call regcache_mark_dirty() to
let the core know about this.

Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
drivers/base/regmap/internal.h
drivers/base/regmap/regcache.c
drivers/base/regmap/regmap.c
include/linux/regmap.h

index 348ff02eb93e02a66887b59995900335f7214fc0..6483e0bda0cfb97a48489f13a30e55c36c893e47 100644 (file)
@@ -74,6 +74,7 @@ struct regmap {
        struct reg_default *reg_defaults;
        const void *reg_defaults_raw;
        void *cache;
+       bool cache_dirty;
 };
 
 struct regcache_ops {
index 666f6f5011dc85339287f9b982f991e22081626b..6ab9f0384d82c3fa82f6c575d45dac31d4b305ca 100644 (file)
@@ -241,6 +241,8 @@ int regcache_sync(struct regmap *map)
                map->cache_ops->name);
        name = map->cache_ops->name;
        trace_regcache_sync(map->dev, name, "start");
+       if (!map->cache_dirty)
+               goto out;
        if (map->cache_ops->sync) {
                ret = map->cache_ops->sync(map);
        } else {
@@ -290,6 +292,23 @@ void regcache_cache_only(struct regmap *map, bool enable)
 }
 EXPORT_SYMBOL_GPL(regcache_cache_only);
 
+/**
+ * regcache_mark_dirty: Mark the register cache as dirty
+ *
+ * @map: map to mark
+ *
+ * Mark the register cache as dirty, for example due to the device
+ * having been powered down for suspend.  If the cache is not marked
+ * as dirty then the cache sync will be suppressed.
+ */
+void regcache_mark_dirty(struct regmap *map)
+{
+       mutex_lock(&map->lock);
+       map->cache_dirty = true;
+       mutex_unlock(&map->lock);
+}
+EXPORT_SYMBOL_GPL(regcache_mark_dirty);
+
 /**
  * regcache_cache_bypass: Put a register map into cache bypass mode
  *
index bf441db1ee90af507ac3597e6a32dd1a3cbfec10..3aca18dbf367389c4e35cac5c38b47d943ee24e4 100644 (file)
@@ -306,8 +306,10 @@ int _regmap_write(struct regmap *map, unsigned int reg,
                ret = regcache_write(map, reg, val);
                if (ret != 0)
                        return ret;
-               if (map->cache_only)
+               if (map->cache_only) {
+                       map->cache_dirty = true;
                        return 0;
+               }
        }
 
        trace_regmap_reg_write(map->dev, reg, val);
index 690276a642cf75dd5dbfcd1d620b8a94880714fc..32043a9749e68def3b7486eeb5ef15232d6d299e 100644 (file)
@@ -143,5 +143,6 @@ int regmap_update_bits(struct regmap *map, unsigned int reg,
 int regcache_sync(struct regmap *map);
 void regcache_cache_only(struct regmap *map, bool enable);
 void regcache_cache_bypass(struct regmap *map, bool enable);
+void regcache_mark_dirty(struct regmap *map);
 
 #endif