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
regmap_fsi32_reg_read(void * context,unsigned int reg,unsigned int * val)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
regmap_fsi32_reg_write(void * context,unsigned int reg,unsigned int val)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
regmap_fsi32le_reg_read(void * context,unsigned int reg,unsigned int * val)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
regmap_fsi32le_reg_write(void * context,unsigned int reg,unsigned int val)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
regmap_fsi16_reg_read(void * context,unsigned int reg,unsigned int * val)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
regmap_fsi16_reg_write(void * context,unsigned int reg,unsigned int val)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
regmap_fsi16le_reg_read(void * context,unsigned int reg,unsigned int * val)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
regmap_fsi16le_reg_write(void * context,unsigned int reg,unsigned int val)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
regmap_fsi8_reg_read(void * context,unsigned int reg,unsigned int * val)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
regmap_fsi8_reg_write(void * context,unsigned int reg,unsigned int val)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
regmap_get_fsi_bus(struct fsi_device * fsi_dev,const struct regmap_config * config)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 = ®map_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 = ®map_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 = ®map_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 = ®map_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 = ®map_fsi32;
195 break;
196 default:
197 break;
198 }
199 break;
200 }
201 }
202
203 return bus ?: ERR_PTR(-EOPNOTSUPP);
204 }
205
__regmap_init_fsi(struct fsi_device * fsi_dev,const struct regmap_config * config,struct lock_class_key * lock_key,const char * lock_name)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
__devm_regmap_init_fsi(struct fsi_device * fsi_dev,const struct regmap_config * config,struct lock_class_key * lock_key,const char * lock_name)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