* [PATCH 1/3] regmap: Supply ranges to the sync operations
@ 2012-02-24 13:38 Mark Brown
2012-02-24 13:38 ` [PATCH 2/3] regmap: Allow drivers to sync only part of the register cache Mark Brown
2012-02-24 13:38 ` [PATCH 3/3] regmap: Add stub for regcache_sync_region() Mark Brown
0 siblings, 2 replies; 3+ messages in thread
From: Mark Brown @ 2012-02-24 13:38 UTC (permalink / raw)
To: linux-kernel; +Cc: patches, Mark Brown
In order to allow us to support partial sync operations add minimum and
maximum register arguments to the sync operation and update the rbtree
and lzo caches to use this new information. The LZO implementation is
obviously not good, we could exit the iteration earlier, but there may
be room for more wide reaching optimisation there.
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
---
drivers/base/regmap/internal.h | 2 +-
drivers/base/regmap/regcache-lzo.c | 10 ++++++++--
drivers/base/regmap/regcache-rbtree.c | 25 ++++++++++++++++++++++---
drivers/base/regmap/regcache.c | 2 +-
4 files changed, 32 insertions(+), 7 deletions(-)
diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h
index abd7667..fcafc5b 100644
--- a/drivers/base/regmap/internal.h
+++ b/drivers/base/regmap/internal.h
@@ -88,7 +88,7 @@ struct regcache_ops {
int (*exit)(struct regmap *map);
int (*read)(struct regmap *map, unsigned int reg, unsigned int *value);
int (*write)(struct regmap *map, unsigned int reg, unsigned int value);
- int (*sync)(struct regmap *map);
+ int (*sync)(struct regmap *map, unsigned int min, unsigned int max);
};
bool regmap_writeable(struct regmap *map, unsigned int reg);
diff --git a/drivers/base/regmap/regcache-lzo.c b/drivers/base/regmap/regcache-lzo.c
index 3025cf9..77dc532 100644
--- a/drivers/base/regmap/regcache-lzo.c
+++ b/drivers/base/regmap/regcache-lzo.c
@@ -331,7 +331,8 @@ out:
return ret;
}
-static int regcache_lzo_sync(struct regmap *map)
+static int regcache_lzo_sync(struct regmap *map, unsigned int min,
+ unsigned int max)
{
struct regcache_lzo_ctx **lzo_blocks;
unsigned int val;
@@ -339,7 +340,12 @@ static int regcache_lzo_sync(struct regmap *map)
int ret;
lzo_blocks = map->cache;
- for_each_set_bit(i, lzo_blocks[0]->sync_bmp, lzo_blocks[0]->sync_bmp_nbits) {
+ i = min;
+ for_each_set_bit_from(i, lzo_blocks[0]->sync_bmp,
+ lzo_blocks[0]->sync_bmp_nbits) {
+ if (i > max)
+ continue;
+
ret = regcache_read(map, i, &val);
if (ret)
return ret;
diff --git a/drivers/base/regmap/regcache-rbtree.c b/drivers/base/regmap/regcache-rbtree.c
index 32620c4..bae183c 100644
--- a/drivers/base/regmap/regcache-rbtree.c
+++ b/drivers/base/regmap/regcache-rbtree.c
@@ -357,7 +357,8 @@ static int regcache_rbtree_write(struct regmap *map, unsigned int reg,
return 0;
}
-static int regcache_rbtree_sync(struct regmap *map)
+static int regcache_rbtree_sync(struct regmap *map, unsigned int min,
+ unsigned int max)
{
struct regcache_rbtree_ctx *rbtree_ctx;
struct rb_node *node;
@@ -365,12 +366,30 @@ static int regcache_rbtree_sync(struct regmap *map)
unsigned int regtmp;
unsigned int val;
int ret;
- int i;
+ int i, base, end;
rbtree_ctx = map->cache;
for (node = rb_first(&rbtree_ctx->root); node; node = rb_next(node)) {
rbnode = rb_entry(node, struct regcache_rbtree_node, node);
- for (i = 0; i < rbnode->blklen; i++) {
+
+ if (rbnode->base_reg < min)
+ continue;
+ if (rbnode->base_reg > max)
+ break;
+ if (rbnode->base_reg + rbnode->blklen < min)
+ continue;
+
+ if (min < rbnode->base_reg + rbnode->blklen)
+ base = min - rbnode->base_reg;
+ else
+ base = 0;
+
+ if (max < rbnode->base_reg + rbnode->blklen)
+ end = rbnode->base_reg + rbnode->blklen - max;
+ else
+ end = rbnode->blklen;
+
+ for (i = base; i < end; i++) {
regtmp = rbnode->base_reg + i;
val = regcache_rbtree_get_register(rbnode, i,
map->cache_word_size);
diff --git a/drivers/base/regmap/regcache.c b/drivers/base/regmap/regcache.c
index 11198e4..002916e 100644
--- a/drivers/base/regmap/regcache.c
+++ b/drivers/base/regmap/regcache.c
@@ -286,7 +286,7 @@ int regcache_sync(struct regmap *map)
}
map->cache_bypass = 0;
- ret = map->cache_ops->sync(map);
+ ret = map->cache_ops->sync(map, 0, map->max_register);
if (ret == 0)
map->cache_dirty = false;
--
1.7.9.1
^ permalink raw reply [flat|nested] 3+ messages in thread
* [PATCH 2/3] regmap: Allow drivers to sync only part of the register cache
2012-02-24 13:38 [PATCH 1/3] regmap: Supply ranges to the sync operations Mark Brown
@ 2012-02-24 13:38 ` Mark Brown
2012-02-24 13:38 ` [PATCH 3/3] regmap: Add stub for regcache_sync_region() Mark Brown
1 sibling, 0 replies; 3+ messages in thread
From: Mark Brown @ 2012-02-24 13:38 UTC (permalink / raw)
To: linux-kernel; +Cc: patches, Mark Brown
Provide a regcache_sync_region() operation which allows drivers to
write only part of the cache back to the hardware. This is intended
for use in cases like power domains or DSP memories where part of the
device register map may be reset without fully resetting the device.
Fully supporting these devices is likely to require additional work to
make specific regions of the register map cache only while they are in
reset, but this is enough for most devices.
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
---
drivers/base/regmap/regcache.c | 45 ++++++++++++++++++++++++++++++++++++++++
include/linux/regmap.h | 2 +
2 files changed, 47 insertions(+), 0 deletions(-)
diff --git a/drivers/base/regmap/regcache.c b/drivers/base/regmap/regcache.c
index 002916e..938cb1d 100644
--- a/drivers/base/regmap/regcache.c
+++ b/drivers/base/regmap/regcache.c
@@ -302,6 +302,51 @@ out:
EXPORT_SYMBOL_GPL(regcache_sync);
/**
+ * regcache_sync_region: Sync part of the register cache with the hardware.
+ *
+ * @map: map to sync.
+ * @min: first register to sync
+ * @max: last register to sync
+ *
+ * Write all non-default register values in the specified region to
+ * the hardware.
+ *
+ * Return a negative value on failure, 0 on success.
+ */
+int regcache_sync_region(struct regmap *map, unsigned int min,
+ unsigned int max)
+{
+ int ret = 0;
+ const char *name;
+ unsigned int bypass;
+
+ BUG_ON(!map->cache_ops || !map->cache_ops->sync);
+
+ mutex_lock(&map->lock);
+
+ /* Remember the initial bypass state */
+ bypass = map->cache_bypass;
+
+ name = map->cache_ops->name;
+ dev_dbg(map->dev, "Syncing %s cache from %d-%d\n", name, min, max);
+
+ trace_regcache_sync(map->dev, name, "start region");
+
+ if (!map->cache_dirty)
+ goto out;
+
+ ret = map->cache_ops->sync(map, min, max);
+
+out:
+ trace_regcache_sync(map->dev, name, "stop region");
+ /* Restore the bypass state */
+ map->cache_bypass = bypass;
+ mutex_unlock(&map->lock);
+
+ return ret;
+}
+
+/**
* regcache_cache_only: Put a register map into cache only mode
*
* @map: map to configure
diff --git a/include/linux/regmap.h b/include/linux/regmap.h
index df9ffcc..c500c64 100644
--- a/include/linux/regmap.h
+++ b/include/linux/regmap.h
@@ -160,6 +160,8 @@ int regmap_update_bits_check(struct regmap *map, unsigned int reg,
int regmap_get_val_bytes(struct regmap *map);
int regcache_sync(struct regmap *map);
+int regcache_sync_region(struct regmap *map, unsigned int min,
+ unsigned int max);
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);
--
1.7.9.1
^ permalink raw reply [flat|nested] 3+ messages in thread
* [PATCH 3/3] regmap: Add stub for regcache_sync_region()
2012-02-24 13:38 [PATCH 1/3] regmap: Supply ranges to the sync operations Mark Brown
2012-02-24 13:38 ` [PATCH 2/3] regmap: Allow drivers to sync only part of the register cache Mark Brown
@ 2012-02-24 13:38 ` Mark Brown
1 sibling, 0 replies; 3+ messages in thread
From: Mark Brown @ 2012-02-24 13:38 UTC (permalink / raw)
To: linux-kernel; +Cc: patches, Mark Brown
Added on another branch.
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
---
include/linux/regmap.h | 7 +++++++
1 files changed, 7 insertions(+), 0 deletions(-)
diff --git a/include/linux/regmap.h b/include/linux/regmap.h
index c500c64..4cd8035 100644
--- a/include/linux/regmap.h
+++ b/include/linux/regmap.h
@@ -296,6 +296,13 @@ static inline int regcache_sync(struct regmap *map)
return -EINVAL;
}
+static inline int regcache_sync_region(struct regmap *map, unsigned int min,
+ unsigned int max)
+{
+ WARN_ONCE(1, "regmap API is disabled");
+ return -EINVAL;
+}
+
static inline void regcache_cache_only(struct regmap *map, bool enable)
{
WARN_ONCE(1, "regmap API is disabled");
--
1.7.9.1
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2012-02-24 13:38 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-02-24 13:38 [PATCH 1/3] regmap: Supply ranges to the sync operations Mark Brown
2012-02-24 13:38 ` [PATCH 2/3] regmap: Allow drivers to sync only part of the register cache Mark Brown
2012-02-24 13:38 ` [PATCH 3/3] regmap: Add stub for regcache_sync_region() Mark Brown
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®