Merge tag 'dma-mapping-6.6-2023-08-29' of git://git.infradead.org/users/hch/dma-mapping
[linux-2.6-microblaze.git] / drivers / base / regmap / regmap-fsi.c
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");