Merge tag 'dt-5.15' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc
[linux-2.6-microblaze.git] / drivers / base / regmap / regmap-mmio.c
1 // SPDX-License-Identifier: GPL-2.0
2 //
3 // Register map access API - MMIO support
4 //
5 // Copyright (c) 2012, NVIDIA CORPORATION.  All rights reserved.
6
7 #include <linux/clk.h>
8 #include <linux/err.h>
9 #include <linux/io.h>
10 #include <linux/module.h>
11 #include <linux/regmap.h>
12 #include <linux/slab.h>
13
14 #include "internal.h"
15
16 struct regmap_mmio_context {
17         void __iomem *regs;
18         unsigned int val_bytes;
19         bool relaxed_mmio;
20
21         bool attached_clk;
22         struct clk *clk;
23
24         void (*reg_write)(struct regmap_mmio_context *ctx,
25                           unsigned int reg, unsigned int val);
26         unsigned int (*reg_read)(struct regmap_mmio_context *ctx,
27                                  unsigned int reg);
28 };
29
30 static int regmap_mmio_regbits_check(size_t reg_bits)
31 {
32         switch (reg_bits) {
33         case 8:
34         case 16:
35         case 32:
36 #ifdef CONFIG_64BIT
37         case 64:
38 #endif
39                 return 0;
40         default:
41                 return -EINVAL;
42         }
43 }
44
45 static int regmap_mmio_get_min_stride(size_t val_bits)
46 {
47         int min_stride;
48
49         switch (val_bits) {
50         case 8:
51                 /* The core treats 0 as 1 */
52                 min_stride = 0;
53                 return 0;
54         case 16:
55                 min_stride = 2;
56                 break;
57         case 32:
58                 min_stride = 4;
59                 break;
60 #ifdef CONFIG_64BIT
61         case 64:
62                 min_stride = 8;
63                 break;
64 #endif
65         default:
66                 return -EINVAL;
67         }
68
69         return min_stride;
70 }
71
72 static void regmap_mmio_write8(struct regmap_mmio_context *ctx,
73                                 unsigned int reg,
74                                 unsigned int val)
75 {
76         writeb(val, ctx->regs + reg);
77 }
78
79 static void regmap_mmio_write8_relaxed(struct regmap_mmio_context *ctx,
80                                 unsigned int reg,
81                                 unsigned int val)
82 {
83         writeb_relaxed(val, ctx->regs + reg);
84 }
85
86 static void regmap_mmio_write16le(struct regmap_mmio_context *ctx,
87                                   unsigned int reg,
88                                   unsigned int val)
89 {
90         writew(val, ctx->regs + reg);
91 }
92
93 static void regmap_mmio_write16le_relaxed(struct regmap_mmio_context *ctx,
94                                   unsigned int reg,
95                                   unsigned int val)
96 {
97         writew_relaxed(val, ctx->regs + reg);
98 }
99
100 static void regmap_mmio_write16be(struct regmap_mmio_context *ctx,
101                                   unsigned int reg,
102                                   unsigned int val)
103 {
104         iowrite16be(val, ctx->regs + reg);
105 }
106
107 static void regmap_mmio_write32le(struct regmap_mmio_context *ctx,
108                                   unsigned int reg,
109                                   unsigned int val)
110 {
111         writel(val, ctx->regs + reg);
112 }
113
114 static void regmap_mmio_write32le_relaxed(struct regmap_mmio_context *ctx,
115                                   unsigned int reg,
116                                   unsigned int val)
117 {
118         writel_relaxed(val, ctx->regs + reg);
119 }
120
121 static void regmap_mmio_write32be(struct regmap_mmio_context *ctx,
122                                   unsigned int reg,
123                                   unsigned int val)
124 {
125         iowrite32be(val, ctx->regs + reg);
126 }
127
128 #ifdef CONFIG_64BIT
129 static void regmap_mmio_write64le(struct regmap_mmio_context *ctx,
130                                   unsigned int reg,
131                                   unsigned int val)
132 {
133         writeq(val, ctx->regs + reg);
134 }
135
136 static void regmap_mmio_write64le_relaxed(struct regmap_mmio_context *ctx,
137                                   unsigned int reg,
138                                   unsigned int val)
139 {
140         writeq_relaxed(val, ctx->regs + reg);
141 }
142 #endif
143
144 static int regmap_mmio_write(void *context, unsigned int reg, unsigned int val)
145 {
146         struct regmap_mmio_context *ctx = context;
147         int ret;
148
149         if (!IS_ERR(ctx->clk)) {
150                 ret = clk_enable(ctx->clk);
151                 if (ret < 0)
152                         return ret;
153         }
154
155         ctx->reg_write(ctx, reg, val);
156
157         if (!IS_ERR(ctx->clk))
158                 clk_disable(ctx->clk);
159
160         return 0;
161 }
162
163 static unsigned int regmap_mmio_read8(struct regmap_mmio_context *ctx,
164                                       unsigned int reg)
165 {
166         return readb(ctx->regs + reg);
167 }
168
169 static unsigned int regmap_mmio_read8_relaxed(struct regmap_mmio_context *ctx,
170                                       unsigned int reg)
171 {
172         return readb_relaxed(ctx->regs + reg);
173 }
174
175 static unsigned int regmap_mmio_read16le(struct regmap_mmio_context *ctx,
176                                          unsigned int reg)
177 {
178         return readw(ctx->regs + reg);
179 }
180
181 static unsigned int regmap_mmio_read16le_relaxed(struct regmap_mmio_context *ctx,
182                                                  unsigned int reg)
183 {
184         return readw_relaxed(ctx->regs + reg);
185 }
186
187 static unsigned int regmap_mmio_read16be(struct regmap_mmio_context *ctx,
188                                          unsigned int reg)
189 {
190         return ioread16be(ctx->regs + reg);
191 }
192
193 static unsigned int regmap_mmio_read32le(struct regmap_mmio_context *ctx,
194                                          unsigned int reg)
195 {
196         return readl(ctx->regs + reg);
197 }
198
199 static unsigned int regmap_mmio_read32le_relaxed(struct regmap_mmio_context *ctx,
200                                                  unsigned int reg)
201 {
202         return readl_relaxed(ctx->regs + reg);
203 }
204
205 static unsigned int regmap_mmio_read32be(struct regmap_mmio_context *ctx,
206                                          unsigned int reg)
207 {
208         return ioread32be(ctx->regs + reg);
209 }
210
211 #ifdef CONFIG_64BIT
212 static unsigned int regmap_mmio_read64le(struct regmap_mmio_context *ctx,
213                                          unsigned int reg)
214 {
215         return readq(ctx->regs + reg);
216 }
217
218 static unsigned int regmap_mmio_read64le_relaxed(struct regmap_mmio_context *ctx,
219                                                  unsigned int reg)
220 {
221         return readq_relaxed(ctx->regs + reg);
222 }
223 #endif
224
225 static int regmap_mmio_read(void *context, unsigned int reg, unsigned int *val)
226 {
227         struct regmap_mmio_context *ctx = context;
228         int ret;
229
230         if (!IS_ERR(ctx->clk)) {
231                 ret = clk_enable(ctx->clk);
232                 if (ret < 0)
233                         return ret;
234         }
235
236         *val = ctx->reg_read(ctx, reg);
237
238         if (!IS_ERR(ctx->clk))
239                 clk_disable(ctx->clk);
240
241         return 0;
242 }
243
244 static void regmap_mmio_free_context(void *context)
245 {
246         struct regmap_mmio_context *ctx = context;
247
248         if (!IS_ERR(ctx->clk)) {
249                 clk_unprepare(ctx->clk);
250                 if (!ctx->attached_clk)
251                         clk_put(ctx->clk);
252         }
253         kfree(context);
254 }
255
256 static const struct regmap_bus regmap_mmio = {
257         .fast_io = true,
258         .reg_write = regmap_mmio_write,
259         .reg_read = regmap_mmio_read,
260         .free_context = regmap_mmio_free_context,
261         .val_format_endian_default = REGMAP_ENDIAN_LITTLE,
262 };
263
264 static struct regmap_mmio_context *regmap_mmio_gen_context(struct device *dev,
265                                         const char *clk_id,
266                                         void __iomem *regs,
267                                         const struct regmap_config *config)
268 {
269         struct regmap_mmio_context *ctx;
270         int min_stride;
271         int ret;
272
273         ret = regmap_mmio_regbits_check(config->reg_bits);
274         if (ret)
275                 return ERR_PTR(ret);
276
277         if (config->pad_bits)
278                 return ERR_PTR(-EINVAL);
279
280         min_stride = regmap_mmio_get_min_stride(config->val_bits);
281         if (min_stride < 0)
282                 return ERR_PTR(min_stride);
283
284         if (config->reg_stride < min_stride)
285                 return ERR_PTR(-EINVAL);
286
287         ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
288         if (!ctx)
289                 return ERR_PTR(-ENOMEM);
290
291         ctx->regs = regs;
292         ctx->val_bytes = config->val_bits / 8;
293         ctx->relaxed_mmio = config->use_relaxed_mmio;
294         ctx->clk = ERR_PTR(-ENODEV);
295
296         switch (regmap_get_val_endian(dev, &regmap_mmio, config)) {
297         case REGMAP_ENDIAN_DEFAULT:
298         case REGMAP_ENDIAN_LITTLE:
299 #ifdef __LITTLE_ENDIAN
300         case REGMAP_ENDIAN_NATIVE:
301 #endif
302                 switch (config->val_bits) {
303                 case 8:
304                         if (ctx->relaxed_mmio) {
305                                 ctx->reg_read = regmap_mmio_read8_relaxed;
306                                 ctx->reg_write = regmap_mmio_write8_relaxed;
307                         } else {
308                                 ctx->reg_read = regmap_mmio_read8;
309                                 ctx->reg_write = regmap_mmio_write8;
310                         }
311                         break;
312                 case 16:
313                         if (ctx->relaxed_mmio) {
314                                 ctx->reg_read = regmap_mmio_read16le_relaxed;
315                                 ctx->reg_write = regmap_mmio_write16le_relaxed;
316                         } else {
317                                 ctx->reg_read = regmap_mmio_read16le;
318                                 ctx->reg_write = regmap_mmio_write16le;
319                         }
320                         break;
321                 case 32:
322                         if (ctx->relaxed_mmio) {
323                                 ctx->reg_read = regmap_mmio_read32le_relaxed;
324                                 ctx->reg_write = regmap_mmio_write32le_relaxed;
325                         } else {
326                                 ctx->reg_read = regmap_mmio_read32le;
327                                 ctx->reg_write = regmap_mmio_write32le;
328                         }
329                         break;
330 #ifdef CONFIG_64BIT
331                 case 64:
332                         if (ctx->relaxed_mmio) {
333                                 ctx->reg_read = regmap_mmio_read64le_relaxed;
334                                 ctx->reg_write = regmap_mmio_write64le_relaxed;
335                         } else {
336                                 ctx->reg_read = regmap_mmio_read64le;
337                                 ctx->reg_write = regmap_mmio_write64le;
338                         }
339                         break;
340 #endif
341                 default:
342                         ret = -EINVAL;
343                         goto err_free;
344                 }
345                 break;
346         case REGMAP_ENDIAN_BIG:
347 #ifdef __BIG_ENDIAN
348         case REGMAP_ENDIAN_NATIVE:
349 #endif
350                 switch (config->val_bits) {
351                 case 8:
352                         ctx->reg_read = regmap_mmio_read8;
353                         ctx->reg_write = regmap_mmio_write8;
354                         break;
355                 case 16:
356                         ctx->reg_read = regmap_mmio_read16be;
357                         ctx->reg_write = regmap_mmio_write16be;
358                         break;
359                 case 32:
360                         ctx->reg_read = regmap_mmio_read32be;
361                         ctx->reg_write = regmap_mmio_write32be;
362                         break;
363                 default:
364                         ret = -EINVAL;
365                         goto err_free;
366                 }
367                 break;
368         default:
369                 ret = -EINVAL;
370                 goto err_free;
371         }
372
373         if (clk_id == NULL)
374                 return ctx;
375
376         ctx->clk = clk_get(dev, clk_id);
377         if (IS_ERR(ctx->clk)) {
378                 ret = PTR_ERR(ctx->clk);
379                 goto err_free;
380         }
381
382         ret = clk_prepare(ctx->clk);
383         if (ret < 0) {
384                 clk_put(ctx->clk);
385                 goto err_free;
386         }
387
388         return ctx;
389
390 err_free:
391         kfree(ctx);
392
393         return ERR_PTR(ret);
394 }
395
396 struct regmap *__regmap_init_mmio_clk(struct device *dev, const char *clk_id,
397                                       void __iomem *regs,
398                                       const struct regmap_config *config,
399                                       struct lock_class_key *lock_key,
400                                       const char *lock_name)
401 {
402         struct regmap_mmio_context *ctx;
403
404         ctx = regmap_mmio_gen_context(dev, clk_id, regs, config);
405         if (IS_ERR(ctx))
406                 return ERR_CAST(ctx);
407
408         return __regmap_init(dev, &regmap_mmio, ctx, config,
409                              lock_key, lock_name);
410 }
411 EXPORT_SYMBOL_GPL(__regmap_init_mmio_clk);
412
413 struct regmap *__devm_regmap_init_mmio_clk(struct device *dev,
414                                            const char *clk_id,
415                                            void __iomem *regs,
416                                            const struct regmap_config *config,
417                                            struct lock_class_key *lock_key,
418                                            const char *lock_name)
419 {
420         struct regmap_mmio_context *ctx;
421
422         ctx = regmap_mmio_gen_context(dev, clk_id, regs, config);
423         if (IS_ERR(ctx))
424                 return ERR_CAST(ctx);
425
426         return __devm_regmap_init(dev, &regmap_mmio, ctx, config,
427                                   lock_key, lock_name);
428 }
429 EXPORT_SYMBOL_GPL(__devm_regmap_init_mmio_clk);
430
431 int regmap_mmio_attach_clk(struct regmap *map, struct clk *clk)
432 {
433         struct regmap_mmio_context *ctx = map->bus_context;
434
435         ctx->clk = clk;
436         ctx->attached_clk = true;
437
438         return clk_prepare(ctx->clk);
439 }
440 EXPORT_SYMBOL_GPL(regmap_mmio_attach_clk);
441
442 void regmap_mmio_detach_clk(struct regmap *map)
443 {
444         struct regmap_mmio_context *ctx = map->bus_context;
445
446         clk_unprepare(ctx->clk);
447
448         ctx->attached_clk = false;
449         ctx->clk = NULL;
450 }
451 EXPORT_SYMBOL_GPL(regmap_mmio_detach_clk);
452
453 MODULE_LICENSE("GPL v2");