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(slave: context, addr: reg, val: &v, size: 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(slave: context, addr: reg, val: &v, size: 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(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 | |
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(slave: context, addr: reg, val: &v, size: 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(slave: context, addr: reg, val: &v, size: 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(slave: context, addr: reg, val: &v, size: 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(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 | |
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(slave: context, addr: reg, val: &v, size: 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(slave: context, addr: reg, val: &v, size: 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(slave: context, addr: reg, val: &v, size: 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 = ®map_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 = ®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(dev: &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(error: -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(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 | } |
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(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 | } |
229 | EXPORT_SYMBOL_GPL(__devm_regmap_init_fsi); |
230 | |
231 | MODULE_LICENSE("GPL" ); |
232 | |