1 // SPDX-License-Identifier: GPL-2.0 2 // 3 // Register cache access API - flat caching support 4 // 5 // Copyright 2012 Wolfson Microelectronics plc 6 // 7 // Author: Mark Brown <broonie@opensource.wolfsonmicro.com> 8 9 #include <linux/bitmap.h> 10 #include <linux/bitops.h> 11 #include <linux/device.h> 12 #include <linux/limits.h> 13 #include <linux/overflow.h> 14 #include <linux/seq_file.h> 15 #include <linux/slab.h> 16 17 #include "internal.h" 18 19 static inline unsigned int regcache_flat_get_index(const struct regmap *map, 20 unsigned int reg) 21 { 22 return regcache_get_index_by_order(map, reg); 23 } 24 25 struct regcache_flat_data { 26 unsigned long *valid; 27 unsigned int data[]; 28 }; 29 30 static int regcache_flat_init(struct regmap *map) 31 { 32 unsigned int cache_size; 33 struct regcache_flat_data *cache; 34 35 if (!map || map->reg_stride_order < 0 || !map->max_register_is_set) 36 return -EINVAL; 37 38 cache_size = regcache_flat_get_index(map, map->max_register) + 1; 39 cache = kzalloc(struct_size(cache, data, cache_size), map->alloc_flags); 40 if (!cache) 41 return -ENOMEM; 42 43 cache->valid = bitmap_zalloc(cache_size, map->alloc_flags); 44 if (!cache->valid) 45 goto err_free; 46 47 map->cache = cache; 48 49 return 0; 50 51 err_free: 52 kfree(cache); 53 return -ENOMEM; 54 } 55 56 static int regcache_flat_exit(struct regmap *map) 57 { 58 struct regcache_flat_data *cache = map->cache; 59 60 if (cache) 61 bitmap_free(cache->valid); 62 63 kfree(cache); 64 map->cache = NULL; 65 66 return 0; 67 } 68 69 static int regcache_flat_populate(struct regmap *map) 70 { 71 struct regcache_flat_data *cache = map->cache; 72 unsigned int i; 73 74 for (i = 0; i < map->num_reg_defaults; i++) { 75 unsigned int reg = map->reg_defaults[i].reg; 76 unsigned int index = regcache_flat_get_index(map, reg); 77 78 cache->data[index] = map->reg_defaults[i].def; 79 __set_bit(index, cache->valid); 80 } 81 82 if (map->reg_default_cb) { 83 dev_dbg(map->dev, 84 "Populating regcache_flat using reg_default_cb callback\n"); 85 86 for (i = 0; i <= map->max_register; i += map->reg_stride) { 87 unsigned int index = regcache_flat_get_index(map, i); 88 unsigned int value; 89 90 if (test_bit(index, cache->valid)) 91 continue; 92 93 if (map->reg_default_cb(map->dev, i, &value)) 94 continue; 95 96 cache->data[index] = value; 97 __set_bit(index, cache->valid); 98 } 99 } 100 101 return 0; 102 } 103 104 static int regcache_flat_read(struct regmap *map, 105 unsigned int reg, unsigned int *value) 106 { 107 struct regcache_flat_data *cache = map->cache; 108 unsigned int index = regcache_flat_get_index(map, reg); 109 110 /* legacy behavior: ignore validity, but warn the user */ 111 if (unlikely(!test_bit(index, cache->valid))) 112 dev_warn_once(map->dev, 113 "using zero-initialized flat cache, this may cause unexpected behavior"); 114 115 *value = cache->data[index]; 116 117 return 0; 118 } 119 120 static int regcache_flat_sparse_read(struct regmap *map, 121 unsigned int reg, unsigned int *value) 122 { 123 struct regcache_flat_data *cache = map->cache; 124 unsigned int index = regcache_flat_get_index(map, reg); 125 126 if (unlikely(!test_bit(index, cache->valid))) 127 return -ENOENT; 128 129 *value = cache->data[index]; 130 131 return 0; 132 } 133 134 static int regcache_flat_write(struct regmap *map, unsigned int reg, 135 unsigned int value) 136 { 137 struct regcache_flat_data *cache = map->cache; 138 unsigned int index = regcache_flat_get_index(map, reg); 139 140 cache->data[index] = value; 141 __set_bit(index, cache->valid); 142 143 return 0; 144 } 145 146 static int regcache_flat_drop(struct regmap *map, unsigned int min, 147 unsigned int max) 148 { 149 struct regcache_flat_data *cache = map->cache; 150 unsigned int bitmap_min = regcache_flat_get_index(map, min); 151 unsigned int bitmap_max = regcache_flat_get_index(map, max); 152 153 bitmap_clear(cache->valid, bitmap_min, bitmap_max + 1 - bitmap_min); 154 155 return 0; 156 } 157 158 struct regcache_ops regcache_flat_ops = { 159 .type = REGCACHE_FLAT, 160 .name = "flat", 161 .init = regcache_flat_init, 162 .exit = regcache_flat_exit, 163 .populate = regcache_flat_populate, 164 .read = regcache_flat_read, 165 .write = regcache_flat_write, 166 }; 167 168 struct regcache_ops regcache_flat_sparse_ops = { 169 .type = REGCACHE_FLAT_S, 170 .name = "flat-sparse", 171 .init = regcache_flat_init, 172 .exit = regcache_flat_exit, 173 .populate = regcache_flat_populate, 174 .read = regcache_flat_sparse_read, 175 .write = regcache_flat_write, 176 .drop = regcache_flat_drop, 177 }; 178