projects/linux·blob master · refs

175 lines · 4.1 KiB

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 <[email protected]>
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
19static 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
25struct regcache_flat_data {
26 unsigned long *valid;
27 unsigned int data[];
28};
29
30static 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
51err_free:
52 kfree(cache);
53 return -ENOMEM;
54}
55
56static void 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
67static int regcache_flat_populate(struct regmap *map)
68{
69 struct regcache_flat_data *cache = map->cache;
70 unsigned int i;
71
72 for (i = 0; i < map->num_reg_defaults; i++) {
73 unsigned int reg = map->reg_defaults[i].reg;
74 unsigned int index = regcache_flat_get_index(map, reg);
75
76 cache->data[index] = map->reg_defaults[i].def;
77 __set_bit(index, cache->valid);
78 }
79
80 if (map->reg_default_cb) {
81 dev_dbg(map->dev,
82 "Populating regcache_flat using reg_default_cb callback\n");
83
84 for (i = 0; i <= map->max_register; i += map->reg_stride) {
85 unsigned int index = regcache_flat_get_index(map, i);
86 unsigned int value;
87
88 if (test_bit(index, cache->valid))
89 continue;
90
91 if (map->reg_default_cb(map->dev, i, &value))
92 continue;
93
94 cache->data[index] = value;
95 __set_bit(index, cache->valid);
96 }
97 }
98
99 return 0;
100}
101
102static int regcache_flat_read(struct regmap *map,
103 unsigned int reg, unsigned int *value)
104{
105 struct regcache_flat_data *cache = map->cache;
106 unsigned int index = regcache_flat_get_index(map, reg);
107
108 /* legacy behavior: ignore validity, but warn the user */
109 if (unlikely(!test_bit(index, cache->valid)))
110 dev_warn_once(map->dev,
111 "using zero-initialized flat cache, this may cause unexpected behavior");
112
113 *value = cache->data[index];
114
115 return 0;
116}
117
118static int regcache_flat_sparse_read(struct regmap *map,
119 unsigned int reg, unsigned int *value)
120{
121 struct regcache_flat_data *cache = map->cache;
122 unsigned int index = regcache_flat_get_index(map, reg);
123
124 if (unlikely(!test_bit(index, cache->valid)))
125 return -ENOENT;
126
127 *value = cache->data[index];
128
129 return 0;
130}
131
132static int regcache_flat_write(struct regmap *map, unsigned int reg,
133 unsigned int value)
134{
135 struct regcache_flat_data *cache = map->cache;
136 unsigned int index = regcache_flat_get_index(map, reg);
137
138 cache->data[index] = value;
139 __set_bit(index, cache->valid);
140
141 return 0;
142}
143
144static int regcache_flat_drop(struct regmap *map, unsigned int min,
145 unsigned int max)
146{
147 struct regcache_flat_data *cache = map->cache;
148 unsigned int bitmap_min = regcache_flat_get_index(map, min);
149 unsigned int bitmap_max = regcache_flat_get_index(map, max);
150
151 bitmap_clear(cache->valid, bitmap_min, bitmap_max + 1 - bitmap_min);
152
153 return 0;
154}
155
156struct regcache_ops regcache_flat_ops = {
157 .type = REGCACHE_FLAT,
158 .name = "flat",
159 .init = regcache_flat_init,
160 .exit = regcache_flat_exit,
161 .populate = regcache_flat_populate,
162 .read = regcache_flat_read,
163 .write = regcache_flat_write,
164};
165
166struct regcache_ops regcache_flat_sparse_ops = {
167 .type = REGCACHE_FLAT_S,
168 .name = "flat-sparse",
169 .init = regcache_flat_init,
170 .exit = regcache_flat_exit,
171 .populate = regcache_flat_populate,
172 .read = regcache_flat_sparse_read,
173 .write = regcache_flat_write,
174 .drop = regcache_flat_drop,
175};