Merge branch 'for-linus' of git://git.open-osd.org/linux-open-osd
[pandora-kernel.git] / drivers / base / regmap / regmap.c
index e7adfe7..bf441db 100644 (file)
@@ -146,6 +146,13 @@ 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->cache_type = config->cache_type;
+       map->reg_defaults = config->reg_defaults;
+       map->num_reg_defaults = config->num_reg_defaults;
+       map->num_reg_defaults_raw = config->num_reg_defaults_raw;
+       map->reg_defaults_raw = config->reg_defaults_raw;
+       map->cache_size_raw = (config->val_bits / 8) * config->num_reg_defaults_raw;
+       map->cache_word_size = config->val_bits / 8;
 
        if (config->read_flag_mask || config->write_flag_mask) {
                map->read_flag_mask = config->read_flag_mask;
@@ -208,6 +215,10 @@ struct regmap *regmap_init(struct device *dev,
                goto err_map;
        }
 
+       ret = regcache_init(map);
+       if (ret < 0)
+               goto err_map;
+
        regmap_debugfs_init(map);
 
        return map;
@@ -224,6 +235,7 @@ EXPORT_SYMBOL_GPL(regmap_init);
  */
 void regmap_exit(struct regmap *map)
 {
+       regcache_exit(map);
        regmap_debugfs_exit(map);
        kfree(map->work_buf);
        kfree(map);
@@ -284,12 +296,20 @@ static int _regmap_raw_write(struct regmap *map, unsigned int reg,
        return ret;
 }
 
-static int _regmap_write(struct regmap *map, unsigned int reg,
-                        unsigned int val)
+int _regmap_write(struct regmap *map, unsigned int reg,
+                 unsigned int val)
 {
        int ret;
        BUG_ON(!map->format.format_write && !map->format.format_val);
 
+       if (!map->cache_bypass) {
+               ret = regcache_write(map, reg, val);
+               if (ret != 0)
+                       return ret;
+               if (map->cache_only)
+                       return 0;
+       }
+
        trace_regmap_reg_write(map->dev, reg, val);
 
        if (map->format.format_write) {
@@ -357,6 +377,8 @@ int regmap_raw_write(struct regmap *map, unsigned int reg,
 {
        int ret;
 
+       WARN_ON(map->cache_type != REGCACHE_NONE);
+
        mutex_lock(&map->lock);
 
        ret = _regmap_raw_write(map, reg, val, val_len);
@@ -403,6 +425,15 @@ static int _regmap_read(struct regmap *map, unsigned int reg,
        if (!map->format.parse_val)
                return -EINVAL;
 
+       if (!map->cache_bypass) {
+               ret = regcache_read(map, reg, val);
+               if (ret == 0)
+                       return 0;
+       }
+
+       if (map->cache_only)
+               return -EBUSY;
+
        ret = _regmap_raw_read(map, reg, map->work_buf, map->format.val_bytes);
        if (ret == 0) {
                *val = map->format.parse_val(map->work_buf);
@@ -451,6 +482,14 @@ int regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
                    size_t val_len)
 {
        int ret;
+       int i;
+       bool vol = true;
+
+       for (i = 0; i < val_len / map->format.val_bytes; i++)
+               if (!regmap_volatile(map, reg + i))
+                       vol = false;
+
+       WARN_ON(!vol && map->cache_type != REGCACHE_NONE);
 
        mutex_lock(&map->lock);
 
@@ -478,16 +517,30 @@ int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val,
 {
        int ret, i;
        size_t val_bytes = map->format.val_bytes;
+       bool vol = true;
 
        if (!map->format.parse_val)
                return -EINVAL;
 
-       ret = regmap_raw_read(map, reg, val, val_bytes * val_count);
-       if (ret != 0)
-               return ret;
+       /* Is this a block of volatile registers? */
+       for (i = 0; i < val_count; i++)
+               if (!regmap_volatile(map, reg + i))
+                       vol = false;
 
-       for (i = 0; i < val_count * val_bytes; i += val_bytes)
-               map->format.parse_val(val + i);
+       if (vol || map->cache_type == REGCACHE_NONE) {
+               ret = regmap_raw_read(map, reg, val, val_bytes * val_count);
+               if (ret != 0)
+                       return ret;
+
+               for (i = 0; i < val_count * val_bytes; i += val_bytes)
+                       map->format.parse_val(val + i);
+       } else {
+               for (i = 0; i < val_count; i++) {
+                       ret = regmap_read(map, reg + i, val + (i * val_bytes));
+                       if (ret != 0)
+                               return ret;
+               }
+       }
 
        return 0;
 }