Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/base/regmap/regmap-raw-ram.c
26428 views
1
// SPDX-License-Identifier: GPL-2.0
2
//
3
// Register map access API - Memory region with raw access
4
//
5
// This is intended for testing only
6
//
7
// Copyright (c) 2023, Arm Ltd
8
9
#include <linux/clk.h>
10
#include <linux/err.h>
11
#include <linux/io.h>
12
#include <linux/module.h>
13
#include <linux/regmap.h>
14
#include <linux/slab.h>
15
#include <linux/swab.h>
16
17
#include "internal.h"
18
19
static unsigned int decode_reg(enum regmap_endian endian, const void *reg)
20
{
21
const u16 *r = reg;
22
23
if (endian == REGMAP_ENDIAN_BIG)
24
return be16_to_cpu(*r);
25
else
26
return le16_to_cpu(*r);
27
}
28
29
static int regmap_raw_ram_gather_write(void *context,
30
const void *reg, size_t reg_len,
31
const void *val, size_t val_len)
32
{
33
struct regmap_ram_data *data = context;
34
unsigned int r;
35
u16 *our_buf = (u16 *)data->vals;
36
int i;
37
38
if (reg_len != 2)
39
return -EINVAL;
40
if (val_len % 2)
41
return -EINVAL;
42
43
r = decode_reg(data->reg_endian, reg);
44
if (data->noinc_reg && data->noinc_reg(data, r)) {
45
memcpy(&our_buf[r], val + val_len - 2, 2);
46
data->written[r] = true;
47
} else {
48
memcpy(&our_buf[r], val, val_len);
49
50
for (i = 0; i < val_len / 2; i++)
51
data->written[r + i] = true;
52
}
53
54
return 0;
55
}
56
57
static int regmap_raw_ram_write(void *context, const void *data, size_t count)
58
{
59
return regmap_raw_ram_gather_write(context, data, 2,
60
data + 2, count - 2);
61
}
62
63
static int regmap_raw_ram_read(void *context,
64
const void *reg, size_t reg_len,
65
void *val, size_t val_len)
66
{
67
struct regmap_ram_data *data = context;
68
unsigned int r;
69
u16 *our_buf = (u16 *)data->vals;
70
int i;
71
72
if (reg_len != 2)
73
return -EINVAL;
74
if (val_len % 2)
75
return -EINVAL;
76
77
r = decode_reg(data->reg_endian, reg);
78
if (data->noinc_reg && data->noinc_reg(data, r)) {
79
for (i = 0; i < val_len; i += 2)
80
memcpy(val + i, &our_buf[r], 2);
81
data->read[r] = true;
82
} else {
83
memcpy(val, &our_buf[r], val_len);
84
85
for (i = 0; i < val_len / 2; i++)
86
data->read[r + i] = true;
87
}
88
89
return 0;
90
}
91
92
static void regmap_raw_ram_free_context(void *context)
93
{
94
struct regmap_ram_data *data = context;
95
96
kfree(data->vals);
97
kfree(data->read);
98
kfree(data->written);
99
kfree(data);
100
}
101
102
static const struct regmap_bus regmap_raw_ram = {
103
.fast_io = true,
104
.write = regmap_raw_ram_write,
105
.gather_write = regmap_raw_ram_gather_write,
106
.read = regmap_raw_ram_read,
107
.free_context = regmap_raw_ram_free_context,
108
};
109
110
struct regmap *__regmap_init_raw_ram(struct device *dev,
111
const struct regmap_config *config,
112
struct regmap_ram_data *data,
113
struct lock_class_key *lock_key,
114
const char *lock_name)
115
{
116
struct regmap *map;
117
118
if (config->reg_bits != 16)
119
return ERR_PTR(-EINVAL);
120
121
if (!config->max_register) {
122
pr_crit("No max_register specified for RAM regmap\n");
123
return ERR_PTR(-EINVAL);
124
}
125
126
data->read = kcalloc(config->max_register + 1, sizeof(bool),
127
GFP_KERNEL);
128
if (!data->read)
129
return ERR_PTR(-ENOMEM);
130
131
data->written = kcalloc(config->max_register + 1, sizeof(bool),
132
GFP_KERNEL);
133
if (!data->written)
134
return ERR_PTR(-ENOMEM);
135
136
data->reg_endian = config->reg_format_endian;
137
138
map = __regmap_init(dev, &regmap_raw_ram, data, config,
139
lock_key, lock_name);
140
141
return map;
142
}
143
EXPORT_SYMBOL_GPL(__regmap_init_raw_ram);
144
145
MODULE_DESCRIPTION("Register map access API - Memory region with raw access");
146
MODULE_LICENSE("GPL v2");
147
148