Re: [PATCH V3 1/4] regmap: Use regcache_mark_dirty() to indicate power loss or reset

From: Lars-Peter Clausen
Date: Mon May 04 2015 - 02:38:40 EST


On 05/04/2015 02:00 AM, Kevin Cernekee wrote:
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@xxxxxxxxxx>
Signed-off-by: Kevin Cernekee <cernekee@xxxxxxxxxxxx>
---
drivers/base/regmap/internal.h | 3 +++
drivers/base/regmap/regcache.c | 61 ++++++++++++++++++++++++++++--------------
2 files changed, 44 insertions(+), 20 deletions(-)

diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h
index a13587b5c2be..b2b2849fc6d3 100644
--- a/drivers/base/regmap/internal.h
+++ b/drivers/base/regmap/internal.h
@@ -131,7 +131,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 7eb7b3b98794..63af3103d0c6 100644
--- a/drivers/base/regmap/regcache.c
+++ b/drivers/base/regmap/regcache.c
@@ -253,6 +253,9 @@ static int regcache_default_sync(struct regmap *map, unsigned int min,
unsigned int max)
{
unsigned int reg;
+ bool no_sync_defaults = map->no_sync_defaults;
+
+ map->no_sync_defaults = false;

This needs to be done at the end in regcache_sync(), the same place where dirty is set to false.


for (reg = min; reg <= max; reg += map->reg_stride) {
unsigned int val;
@@ -266,10 +269,12 @@ static int regcache_default_sync(struct regmap *map, unsigned int min,
if (ret)
return ret;

- /* Is this the hardware default? If so skip. */
- ret = regcache_lookup_reg(map, reg);
- if (ret >= 0 && val == map->reg_defaults[ret].def)
- continue;
+ if (no_sync_defaults) {
+ /* Is this the hardware default? If so skip. */
+ ret = regcache_lookup_reg(map, reg);
+ if (ret >= 0 && val == map->reg_defaults[ret].def)
+ continue;
+ }

This should go into a helper function regacache_reg_needs_sync() so it can be reused at the other places where the same logic is needed.
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/