]> rtime.felk.cvut.cz Git - sojka/nv-tegra/linux-3.10.git/commitdiff
regmap: cache: Add interface to change volatile attribute
authorAlex Frid <afrid@nvidia.com>
Tue, 11 Feb 2014 01:35:48 +0000 (17:35 -0800)
committerAleksandr Frid <afrid@nvidia.com>
Thu, 13 Feb 2014 19:05:00 +0000 (11:05 -0800)
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>
drivers/base/regmap/internal.h
drivers/base/regmap/regcache.c
drivers/base/regmap/regmap.c
include/linux/regmap.h

index c130536e0ab0626866a41dd23f35d2c260bb9980..1509d963fd87aa12751fe9ecd064b6443b45f90c 100644 (file)
@@ -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)
index 46283fd3c4c0dfb680e7ffe5d7320f6bf6ec581e..c1411838d2aea8378b3ab7ed7374e73947ce9f5e 100644 (file)
@@ -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;
index d0c81d1f409c07bf2bb4eac3f34469a7b9626dd9..0b43b260390bb63e96e1618cf07492dd27487e5e 100644 (file)
@@ -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);
index 61c350d24de07e5a0358e24af4057b2d1d0df693..882d360b9d75692ee2d3bb68b3fed6943a3eacfb 100644 (file)
@@ -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");