summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Frid <afrid@nvidia.com>2014-02-10 17:35:48 -0800
committerAleksandr Frid <afrid@nvidia.com>2014-02-13 11:05:00 -0800
commit7658313e7a7126fbe94d68f738795211ce061dc3 (patch)
treec8ec1f88f933ae02929b1e53ffa9f007e86348e8
parent538b70e2b892b1c24c7f5dc4f3a5e6fe4563fd68 (diff)
regmap: cache: Add interface to change volatile attribute
Defined regmap driver callback to set access attribute for the single register as either volatile or cached. Provided the respective public interface for changing access attribute on top of the callback. Cleared cache present bit to invalidate register cache whenever access is actually changed. Bug 1454969 Change-Id: If4e29ccc4c67892974ab6095f9d82e001198d19d Signed-off-by: Alex Frid <afrid@nvidia.com> Reviewed-on: http://git-master/r/365704 Reviewed-by: Laxman Dewangan <ldewangan@nvidia.com>
-rw-r--r--drivers/base/regmap/internal.h9
-rw-r--r--drivers/base/regmap/regcache.c47
-rw-r--r--drivers/base/regmap/regmap.c2
-rw-r--r--include/linux/regmap.h13
4 files changed, 71 insertions, 0 deletions
diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h
index c130536e0ab0..1509d963fd87 100644
--- a/drivers/base/regmap/internal.h
+++ b/drivers/base/regmap/internal.h
@@ -85,6 +85,8 @@ struct regmap {
bool (*readable_reg)(struct device *dev, unsigned int reg);
bool (*volatile_reg)(struct device *dev, unsigned int reg);
bool (*precious_reg)(struct device *dev, unsigned int reg);
+ int (*reg_volatile_set)(struct device *dev, unsigned int reg,
+ bool is_volatile);
const struct regmap_access_table *wr_table;
const struct regmap_access_table *rd_table;
const struct regmap_access_table *volatile_table;
@@ -210,6 +212,13 @@ bool regcache_set_val(struct regmap *map, void *base, unsigned int idx,
int regcache_lookup_reg(struct regmap *map, unsigned int reg);
int regcache_set_reg_present(struct regmap *map, unsigned int reg);
+static inline void regcache_clear_reg_present(struct regmap *map,
+ unsigned int reg)
+{
+ if ((map->cache_present) && (reg < map->cache_present_nbits))
+ clear_bit(reg, map->cache_present);
+}
+
static inline bool regcache_reg_present(struct regmap *map, unsigned int reg)
{
if (!map->cache_present)
diff --git a/drivers/base/regmap/regcache.c b/drivers/base/regmap/regcache.c
index 46283fd3c4c0..c1411838d2ae 100644
--- a/drivers/base/regmap/regcache.c
+++ b/drivers/base/regmap/regcache.c
@@ -418,6 +418,53 @@ void regcache_cache_bypass(struct regmap *map, bool enable)
}
EXPORT_SYMBOL_GPL(regcache_cache_bypass);
+static int _regcache_volatile_set(struct regmap *map, unsigned int reg,
+ bool is_volatile)
+{
+ int ret;
+
+ if (is_volatile == regmap_volatile(map, reg))
+ return 0;
+
+ if (!map->reg_volatile_set)
+ return -ENOSYS;
+
+ if (!map->cache_present)
+ return -ENOENT;
+
+ ret = map->reg_volatile_set(map->dev, reg, is_volatile);
+ if (ret)
+ return ret;
+
+ regcache_clear_reg_present(map, reg);
+ return 0;
+}
+
+/**
+ * regcache_volatile_set: Set single register as volatile or cached
+ *
+ * @map: map to apply change to
+ * @reg: register to be set as volatile or cached
+ * @is_volatile: if true, register is set as volatile, otherwise as cached
+ *
+ * Set access attribute to the specified register as volatile or cached. Clear
+ * cache_present bit (i.e., invalidate cache) on successful exit.
+ *
+ * Return a negative value on failure, 0 on success.
+ */
+int regcache_volatile_set(struct regmap *map, unsigned int reg,
+ bool is_volatile)
+{
+ int ret;
+
+ map->lock(map->lock_arg);
+ ret = _regcache_volatile_set(map, reg, is_volatile);
+ map->unlock(map->lock_arg);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(regcache_volatile_set);
+
int regcache_set_reg_present(struct regmap *map, unsigned int reg)
{
unsigned long *cache_present;
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
index d0c81d1f409c..0b43b260390b 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -452,6 +452,7 @@ struct regmap *regmap_init(struct device *dev,
map->readable_reg = config->readable_reg;
map->volatile_reg = config->volatile_reg;
map->precious_reg = config->precious_reg;
+ map->reg_volatile_set = config->reg_volatile_set;
map->cache_type = config->cache_type;
map->name = config->name;
@@ -825,6 +826,7 @@ int regmap_reinit_cache(struct regmap *map, const struct regmap_config *config)
map->readable_reg = config->readable_reg;
map->volatile_reg = config->volatile_reg;
map->precious_reg = config->precious_reg;
+ map->reg_volatile_set = config->reg_volatile_set;
map->cache_type = config->cache_type;
regmap_debugfs_init(map, config->name);
diff --git a/include/linux/regmap.h b/include/linux/regmap.h
index 61c350d24de0..882d360b9d75 100644
--- a/include/linux/regmap.h
+++ b/include/linux/regmap.h
@@ -126,6 +126,8 @@ typedef void (*regmap_unlock)(void *);
* field is NULL but precious_table (see below) is not, the
* check is performed on such table (a register is precious if
* it belongs to one of the ranges specified by precious_table).
+ * @reg_volatile_set: Optional callback to change access mode for the register
+ * between volatile and cached.
* @lock: Optional lock callback (overrides regmap's default lock
* function, based on spinlock or mutex).
* @unlock: As above for unlocking.
@@ -189,6 +191,8 @@ struct regmap_config {
bool (*readable_reg)(struct device *dev, unsigned int reg);
bool (*volatile_reg)(struct device *dev, unsigned int reg);
bool (*precious_reg)(struct device *dev, unsigned int reg);
+ int (*reg_volatile_set)(struct device *dev, unsigned int reg,
+ bool is_volatile);
regmap_lock lock;
regmap_unlock unlock;
void *lock_arg;
@@ -401,6 +405,8 @@ int regcache_sync_region(struct regmap *map, unsigned int min,
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);
+int regcache_volatile_set(struct regmap *map, unsigned int reg,
+ bool is_volatile);
int regmap_register_patch(struct regmap *map, const struct reg_default *regs,
int num_regs);
@@ -597,6 +603,13 @@ static inline void regcache_mark_dirty(struct regmap *map)
WARN_ONCE(1, "regmap API is disabled");
}
+static int regcache_volatile_set(struct regmap *map, unsigned int reg,
+ bool is_volatile)
+{
+ WARN_ONCE(1, "regmap API is disabled");
+ return -EINVAL;
+}
+
static inline void regmap_async_complete(struct regmap *map)
{
WARN_ONCE(1, "regmap API is disabled");