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
regcache_flat_get_index(const struct regmap * map,unsigned int reg)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
regcache_flat_init(struct regmap * map)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_flex(*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
regcache_flat_exit(struct regmap * map)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
regcache_flat_populate(struct regmap * map)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
regcache_flat_read(struct regmap * map,unsigned int reg,unsigned int * value)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
regcache_flat_sparse_read(struct regmap * map,unsigned int reg,unsigned int * value)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
regcache_flat_write(struct regmap * map,unsigned int reg,unsigned int value)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
regcache_flat_drop(struct regmap * map,unsigned int min,unsigned int max)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