xref: /openbmc/linux/drivers/base/regmap/regmap-fsi.c (revision d47a97bd)
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 
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