summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKevin Cernekee <cernekee@chromium.org>2015-05-05 15:14:14 -0700
committerShengjiu Wang <shengjiu.wang@freescale.com>2015-07-31 17:51:00 +0800
commitc78e7bf7952ce9c56aecdb0cb960474e7250c463 (patch)
treee63afa088ca11bf4c74a1c1dae8f423d7a6f2ab8
parentf3fcf74117db82f3a11ec8e40bcf8f97271c17ae (diff)
regmap: Use regcache_mark_dirty() to indicate power loss or reset
Existing regmap users call regcache_mark_dirty() as part of the suspend/resume sequence, to tell regcache that non-default values need to be resynced post-resume. Add an internal "no_sync_defaults" regmap flag to remember this state, so that regcache_sync() can differentiate between these two cases: 1) HW was reset, so any cache values that match map->reg_defaults can be safely skipped. On some chips there are a lot of registers in the reg_defaults list, so this optimization speeds things up quite a bit. 2) HW was not reset (maybe it was just clock-gated), so if we cached any writes, they should be sent to the hardware regardless of whether they match the HW default. Currently this will write out all values in the regcache, since we don't maintain per-register dirty bits. Suggested-by: Mark Brown <broonie@kernel.org> Signed-off-by: Kevin Cernekee <cernekee@chromium.org> Signed-off-by: Mark Brown <broonie@kernel.org> (cherry picked from commit 1c79771a7270278e6ff486edf4dfeb8c4fc01ee0)
-rw-r--r--drivers/base/regmap/internal.h3
-rw-r--r--drivers/base/regmap/regcache.c19
2 files changed, 18 insertions, 4 deletions
diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h
index 33414b1de201..c84abd062984 100644
--- a/drivers/base/regmap/internal.h
+++ b/drivers/base/regmap/internal.h
@@ -127,7 +127,10 @@ struct regmap {
struct reg_default *reg_defaults;
const void *reg_defaults_raw;
void *cache;
+ /* if set, the cache contains newer data than the HW */
u32 cache_dirty;
+ /* if set, the HW registers are known to match map->reg_defaults */
+ bool no_sync_defaults;
struct reg_default *patch;
int patch_regs;
diff --git a/drivers/base/regmap/regcache.c b/drivers/base/regmap/regcache.c
index 0cefeafb62b6..980525dff39b 100644
--- a/drivers/base/regmap/regcache.c
+++ b/drivers/base/regmap/regcache.c
@@ -249,6 +249,10 @@ static bool regcache_reg_needs_sync(struct regmap *map, unsigned int reg,
{
int ret;
+ /* If we don't know the chip just got reset, then sync everything. */
+ if (!map->no_sync_defaults)
+ return true;
+
/* Is this the hardware default? If so skip. */
ret = regcache_lookup_reg(map, reg);
if (ret >= 0 && val == map->reg_defaults[ret].def)
@@ -347,6 +351,7 @@ out:
/* Restore the bypass state */
map->async = false;
map->cache_bypass = bypass;
+ map->no_sync_defaults = false;
map->unlock(map->lock_arg);
regmap_async_complete(map);
@@ -402,6 +407,7 @@ out:
/* Restore the bypass state */
map->cache_bypass = bypass;
map->async = false;
+ map->no_sync_defaults = false;
map->unlock(map->lock_arg);
regmap_async_complete(map);
@@ -466,18 +472,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
+ * regcache_mark_dirty: Indicate that HW registers were reset to default values
*
* @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.
+ * Inform regcache that the device has been powered down or reset, so that
+ * on resume, regcache_sync() knows to write out all non-default values
+ * stored in the cache.
+ *
+ * If this function is not called, regcache_sync() will assume that
+ * the hardware state still matches the cache state, modulo any writes that
+ * happened when cache_only was true.
*/
void regcache_mark_dirty(struct regmap *map)
{
map->lock(map->lock_arg);
map->cache_dirty = true;
+ map->no_sync_defaults = true;
map->unlock(map->lock_arg);
}
EXPORT_SYMBOL_GPL(regcache_mark_dirty);