Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/base/regmap/regmap-fsi.c
26428 views
1
// SPDX-License-Identifier: GPL-2.0
2
//
3
// Register map access API - FSI support
4
//
5
// Copyright 2022 IBM Corp
6
//
7
// Author: Eddie James <[email protected]>
8
9
#include <linux/fsi.h>
10
#include <linux/module.h>
11
#include <linux/regmap.h>
12
13
#include "internal.h"
14
15
static int regmap_fsi32_reg_read(void *context, unsigned int reg, unsigned int *val)
16
{
17
u32 v;
18
int ret;
19
20
ret = fsi_slave_read(context, reg, &v, sizeof(v));
21
if (ret)
22
return ret;
23
24
*val = v;
25
return 0;
26
}
27
28
static int regmap_fsi32_reg_write(void *context, unsigned int reg, unsigned int val)
29
{
30
u32 v = val;
31
32
return fsi_slave_write(context, reg, &v, sizeof(v));
33
}
34
35
static const struct regmap_bus regmap_fsi32 = {
36
.reg_write = regmap_fsi32_reg_write,
37
.reg_read = regmap_fsi32_reg_read,
38
};
39
40
static int regmap_fsi32le_reg_read(void *context, unsigned int reg, unsigned int *val)
41
{
42
__be32 v;
43
int ret;
44
45
ret = fsi_slave_read(context, reg, &v, sizeof(v));
46
if (ret)
47
return ret;
48
49
*val = be32_to_cpu(v);
50
return 0;
51
}
52
53
static int regmap_fsi32le_reg_write(void *context, unsigned int reg, unsigned int val)
54
{
55
__be32 v = cpu_to_be32(val);
56
57
return fsi_slave_write(context, reg, &v, sizeof(v));
58
}
59
60
static const struct regmap_bus regmap_fsi32le = {
61
.reg_write = regmap_fsi32le_reg_write,
62
.reg_read = regmap_fsi32le_reg_read,
63
};
64
65
static int regmap_fsi16_reg_read(void *context, unsigned int reg, unsigned int *val)
66
{
67
u16 v;
68
int ret;
69
70
ret = fsi_slave_read(context, reg, &v, sizeof(v));
71
if (ret)
72
return ret;
73
74
*val = v;
75
return 0;
76
}
77
78
static int regmap_fsi16_reg_write(void *context, unsigned int reg, unsigned int val)
79
{
80
u16 v;
81
82
if (val > 0xffff)
83
return -EINVAL;
84
85
v = val;
86
return fsi_slave_write(context, reg, &v, sizeof(v));
87
}
88
89
static const struct regmap_bus regmap_fsi16 = {
90
.reg_write = regmap_fsi16_reg_write,
91
.reg_read = regmap_fsi16_reg_read,
92
};
93
94
static int regmap_fsi16le_reg_read(void *context, unsigned int reg, unsigned int *val)
95
{
96
__be16 v;
97
int ret;
98
99
ret = fsi_slave_read(context, reg, &v, sizeof(v));
100
if (ret)
101
return ret;
102
103
*val = be16_to_cpu(v);
104
return 0;
105
}
106
107
static int regmap_fsi16le_reg_write(void *context, unsigned int reg, unsigned int val)
108
{
109
__be16 v;
110
111
if (val > 0xffff)
112
return -EINVAL;
113
114
v = cpu_to_be16(val);
115
return fsi_slave_write(context, reg, &v, sizeof(v));
116
}
117
118
static const struct regmap_bus regmap_fsi16le = {
119
.reg_write = regmap_fsi16le_reg_write,
120
.reg_read = regmap_fsi16le_reg_read,
121
};
122
123
static int regmap_fsi8_reg_read(void *context, unsigned int reg, unsigned int *val)
124
{
125
u8 v;
126
int ret;
127
128
ret = fsi_slave_read(context, reg, &v, sizeof(v));
129
if (ret)
130
return ret;
131
132
*val = v;
133
return 0;
134
}
135
136
static int regmap_fsi8_reg_write(void *context, unsigned int reg, unsigned int val)
137
{
138
u8 v;
139
140
if (val > 0xff)
141
return -EINVAL;
142
143
v = val;
144
return fsi_slave_write(context, reg, &v, sizeof(v));
145
}
146
147
static const struct regmap_bus regmap_fsi8 = {
148
.reg_write = regmap_fsi8_reg_write,
149
.reg_read = regmap_fsi8_reg_read,
150
};
151
152
static const struct regmap_bus *regmap_get_fsi_bus(struct fsi_device *fsi_dev,
153
const struct regmap_config *config)
154
{
155
const struct regmap_bus *bus = NULL;
156
157
if (config->reg_bits == 8 || config->reg_bits == 16 || config->reg_bits == 32) {
158
switch (config->val_bits) {
159
case 8:
160
bus = &regmap_fsi8;
161
break;
162
case 16:
163
switch (regmap_get_val_endian(&fsi_dev->dev, NULL, config)) {
164
case REGMAP_ENDIAN_LITTLE:
165
#ifdef __LITTLE_ENDIAN
166
case REGMAP_ENDIAN_NATIVE:
167
#endif
168
bus = &regmap_fsi16le;
169
break;
170
case REGMAP_ENDIAN_DEFAULT:
171
case REGMAP_ENDIAN_BIG:
172
#ifdef __BIG_ENDIAN
173
case REGMAP_ENDIAN_NATIVE:
174
#endif
175
bus = &regmap_fsi16;
176
break;
177
default:
178
break;
179
}
180
break;
181
case 32:
182
switch (regmap_get_val_endian(&fsi_dev->dev, NULL, config)) {
183
case REGMAP_ENDIAN_LITTLE:
184
#ifdef __LITTLE_ENDIAN
185
case REGMAP_ENDIAN_NATIVE:
186
#endif
187
bus = &regmap_fsi32le;
188
break;
189
case REGMAP_ENDIAN_DEFAULT:
190
case REGMAP_ENDIAN_BIG:
191
#ifdef __BIG_ENDIAN
192
case REGMAP_ENDIAN_NATIVE:
193
#endif
194
bus = &regmap_fsi32;
195
break;
196
default:
197
break;
198
}
199
break;
200
}
201
}
202
203
return bus ?: ERR_PTR(-EOPNOTSUPP);
204
}
205
206
struct regmap *__regmap_init_fsi(struct fsi_device *fsi_dev, const struct regmap_config *config,
207
struct lock_class_key *lock_key, const char *lock_name)
208
{
209
const struct regmap_bus *bus = regmap_get_fsi_bus(fsi_dev, config);
210
211
if (IS_ERR(bus))
212
return ERR_CAST(bus);
213
214
return __regmap_init(&fsi_dev->dev, bus, fsi_dev->slave, config, lock_key, lock_name);
215
}
216
EXPORT_SYMBOL_GPL(__regmap_init_fsi);
217
218
struct regmap *__devm_regmap_init_fsi(struct fsi_device *fsi_dev,
219
const struct regmap_config *config,
220
struct lock_class_key *lock_key, const char *lock_name)
221
{
222
const struct regmap_bus *bus = regmap_get_fsi_bus(fsi_dev, config);
223
224
if (IS_ERR(bus))
225
return ERR_CAST(bus);
226
227
return __devm_regmap_init(&fsi_dev->dev, bus, fsi_dev->slave, config, lock_key, lock_name);
228
}
229
EXPORT_SYMBOL_GPL(__devm_regmap_init_fsi);
230
231
MODULE_LICENSE("GPL");
232
233