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 <eajames@linux.ibm.com>
8
9#include <linux/fsi.h>
10#include <linux/module.h>
11#include <linux/regmap.h>
12
13#include "internal.h"
14
15static 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(slave: context, addr: reg, val: &v, size: sizeof(v));
21 if (ret)
22 return ret;
23
24 *val = v;
25 return 0;
26}
27
28static int regmap_fsi32_reg_write(void *context, unsigned int reg, unsigned int val)
29{
30 u32 v = val;
31
32 return fsi_slave_write(slave: context, addr: reg, val: &v, size: sizeof(v));
33}
34
35static const struct regmap_bus regmap_fsi32 = {
36 .reg_write = regmap_fsi32_reg_write,
37 .reg_read = regmap_fsi32_reg_read,
38};
39
40static 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(slave: context, addr: reg, val: &v, size: sizeof(v));
46 if (ret)
47 return ret;
48
49 *val = be32_to_cpu(v);
50 return 0;
51}
52
53static 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(slave: context, addr: reg, val: &v, size: sizeof(v));
58}
59
60static const struct regmap_bus regmap_fsi32le = {
61 .reg_write = regmap_fsi32le_reg_write,
62 .reg_read = regmap_fsi32le_reg_read,
63};
64
65static 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(slave: context, addr: reg, val: &v, size: sizeof(v));
71 if (ret)
72 return ret;
73
74 *val = v;
75 return 0;
76}
77
78static 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(slave: context, addr: reg, val: &v, size: sizeof(v));
87}
88
89static const struct regmap_bus regmap_fsi16 = {
90 .reg_write = regmap_fsi16_reg_write,
91 .reg_read = regmap_fsi16_reg_read,
92};
93
94static 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(slave: context, addr: reg, val: &v, size: sizeof(v));
100 if (ret)
101 return ret;
102
103 *val = be16_to_cpu(v);
104 return 0;
105}
106
107static 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(slave: context, addr: reg, val: &v, size: sizeof(v));
116}
117
118static const struct regmap_bus regmap_fsi16le = {
119 .reg_write = regmap_fsi16le_reg_write,
120 .reg_read = regmap_fsi16le_reg_read,
121};
122
123static 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(slave: context, addr: reg, val: &v, size: sizeof(v));
129 if (ret)
130 return ret;
131
132 *val = v;
133 return 0;
134}
135
136static 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(slave: context, addr: reg, val: &v, size: sizeof(v));
145}
146
147static const struct regmap_bus regmap_fsi8 = {
148 .reg_write = regmap_fsi8_reg_write,
149 .reg_read = regmap_fsi8_reg_read,
150};
151
152static 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(dev: &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(dev: &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(error: -EOPNOTSUPP);
204}
205
206struct 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(ptr: bus))
212 return ERR_CAST(ptr: bus);
213
214 return __regmap_init(dev: &fsi_dev->dev, bus, bus_context: fsi_dev->slave, config, lock_key, lock_name);
215}
216EXPORT_SYMBOL_GPL(__regmap_init_fsi);
217
218struct 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(ptr: bus))
225 return ERR_CAST(ptr: bus);
226
227 return __devm_regmap_init(dev: &fsi_dev->dev, bus, bus_context: fsi_dev->slave, config, lock_key, lock_name);
228}
229EXPORT_SYMBOL_GPL(__devm_regmap_init_fsi);
230
231MODULE_LICENSE("GPL");
232

source code of linux/drivers/base/regmap/regmap-fsi.c