Merge tag 'devicetree-for-6.5-2' of git://git.kernel.org/pub/scm/linux/kernel/git...
[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 #include <linux/swab.h>
14
15 #include "internal.h"
16
17 struct regmap_mmio_context {
18         void __iomem *regs;
19         unsigned int val_bytes;
20         bool big_endian;
21
22         bool attached_clk;
23         struct clk *clk;
24
25         void (*reg_write)(struct regmap_mmio_context *ctx,
26                           unsigned int reg, unsigned int val);
27         unsigned int (*reg_read)(struct regmap_mmio_context *ctx,
28                                  unsigned int reg);
29 };
30
31 static int regmap_mmio_regbits_check(size_t reg_bits)
32 {
33         switch (reg_bits) {
34         case 8:
35         case 16:
36         case 32:
37                 return 0;
38         default:
39                 return -EINVAL;
40         }
41 }
42
43 static int regmap_mmio_get_min_stride(size_t val_bits)
44 {
45         int min_stride;
46
47         switch (val_bits) {
48         case 8:
49                 /* The core treats 0 as 1 */
50                 min_stride = 0;
51                 break;
52         case 16:
53                 min_stride = 2;
54                 break;
55         case 32:
56                 min_stride = 4;
57                 break;
58         default:
59                 return -EINVAL;
60         }
61
62         return min_stride;
63 }
64
65 static void regmap_mmio_write8(struct regmap_mmio_context *ctx,
66                                 unsigned int reg,
67                                 unsigned int val)
68 {
69         writeb(val, ctx->regs + reg);
70 }
71
72 static void regmap_mmio_write8_relaxed(struct regmap_mmio_context *ctx,
73                                 unsigned int reg,
74                                 unsigned int val)
75 {
76         writeb_relaxed(val, ctx->regs + reg);
77 }
78
79 static void regmap_mmio_iowrite8(struct regmap_mmio_context *ctx,
80                                  unsigned int reg, unsigned int val)
81 {
82         iowrite8(val, ctx->regs + reg);
83 }
84
85 static void regmap_mmio_write16le(struct regmap_mmio_context *ctx,
86                                   unsigned int reg,
87                                   unsigned int val)
88 {
89         writew(val, ctx->regs + reg);
90 }
91
92 static void regmap_mmio_write16le_relaxed(struct regmap_mmio_context *ctx,
93                                   unsigned int reg,
94                                   unsigned int val)
95 {
96         writew_relaxed(val, ctx->regs + reg);
97 }
98
99 static void regmap_mmio_iowrite16le(struct regmap_mmio_context *ctx,
100                                     unsigned int reg, unsigned int val)
101 {
102         iowrite16(val, ctx->regs + reg);
103 }
104
105 static void regmap_mmio_write16be(struct regmap_mmio_context *ctx,
106                                   unsigned int reg,
107                                   unsigned int val)
108 {
109         writew(swab16(val), ctx->regs + reg);
110 }
111
112 static void regmap_mmio_iowrite16be(struct regmap_mmio_context *ctx,
113                                     unsigned int reg, unsigned int val)
114 {
115         iowrite16be(val, ctx->regs + reg);
116 }
117
118 static void regmap_mmio_write32le(struct regmap_mmio_context *ctx,
119                                   unsigned int reg,
120                                   unsigned int val)
121 {
122         writel(val, ctx->regs + reg);
123 }
124
125 static void regmap_mmio_write32le_relaxed(struct regmap_mmio_context *ctx,
126                                   unsigned int reg,
127                                   unsigned int val)
128 {
129         writel_relaxed(val, ctx->regs + reg);
130 }
131
132 static void regmap_mmio_iowrite32le(struct regmap_mmio_context *ctx,
133                                     unsigned int reg, unsigned int val)
134 {
135         iowrite32(val, ctx->regs + reg);
136 }
137
138 static void regmap_mmio_write32be(struct regmap_mmio_context *ctx,
139                                   unsigned int reg,
140                                   unsigned int val)
141 {
142         writel(swab32(val), ctx->regs + reg);
143 }
144
145 static void regmap_mmio_iowrite32be(struct regmap_mmio_context *ctx,
146                                     unsigned int reg, unsigned int val)
147 {
148         iowrite32be(val, ctx->regs + reg);
149 }
150
151 static int regmap_mmio_write(void *context, unsigned int reg, unsigned int val)
152 {
153         struct regmap_mmio_context *ctx = context;
154         int ret;
155
156         if (!IS_ERR(ctx->clk)) {
157                 ret = clk_enable(ctx->clk);
158                 if (ret < 0)
159                         return ret;
160         }
161
162         ctx->reg_write(ctx, reg, val);
163
164         if (!IS_ERR(ctx->clk))
165                 clk_disable(ctx->clk);
166
167         return 0;
168 }
169
170 static int regmap_mmio_noinc_write(void *context, unsigned int reg,
171                                    const void *val, size_t val_count)
172 {
173         struct regmap_mmio_context *ctx = context;
174         int ret = 0;
175         int i;
176
177         if (!IS_ERR(ctx->clk)) {
178                 ret = clk_enable(ctx->clk);
179                 if (ret < 0)
180                         return ret;
181         }
182
183         /*
184          * There are no native, assembly-optimized write single register
185          * operations for big endian, so fall back to emulation if this
186          * is needed. (Single bytes are fine, they are not affected by
187          * endianness.)
188          */
189         if (ctx->big_endian && (ctx->val_bytes > 1)) {
190                 switch (ctx->val_bytes) {
191                 case 2:
192                 {
193                         const u16 *valp = (const u16 *)val;
194                         for (i = 0; i < val_count; i++)
195                                 writew(swab16(valp[i]), ctx->regs + reg);
196                         goto out_clk;
197                 }
198                 case 4:
199                 {
200                         const u32 *valp = (const u32 *)val;
201                         for (i = 0; i < val_count; i++)
202                                 writel(swab32(valp[i]), ctx->regs + reg);
203                         goto out_clk;
204                 }
205 #ifdef CONFIG_64BIT
206                 case 8:
207                 {
208                         const u64 *valp = (const u64 *)val;
209                         for (i = 0; i < val_count; i++)
210                                 writeq(swab64(valp[i]), ctx->regs + reg);
211                         goto out_clk;
212                 }
213 #endif
214                 default:
215                         ret = -EINVAL;
216                         goto out_clk;
217                 }
218         }
219
220         switch (ctx->val_bytes) {
221         case 1:
222                 writesb(ctx->regs + reg, (const u8 *)val, val_count);
223                 break;
224         case 2:
225                 writesw(ctx->regs + reg, (const u16 *)val, val_count);
226                 break;
227         case 4:
228                 writesl(ctx->regs + reg, (const u32 *)val, val_count);
229                 break;
230 #ifdef CONFIG_64BIT
231         case 8:
232                 writesq(ctx->regs + reg, (const u64 *)val, val_count);
233                 break;
234 #endif
235         default:
236                 ret = -EINVAL;
237                 break;
238         }
239
240 out_clk:
241         if (!IS_ERR(ctx->clk))
242                 clk_disable(ctx->clk);
243
244         return ret;
245 }
246
247 static unsigned int regmap_mmio_read8(struct regmap_mmio_context *ctx,
248                                       unsigned int reg)
249 {
250         return readb(ctx->regs + reg);
251 }
252
253 static unsigned int regmap_mmio_read8_relaxed(struct regmap_mmio_context *ctx,
254                                       unsigned int reg)
255 {
256         return readb_relaxed(ctx->regs + reg);
257 }
258
259 static unsigned int regmap_mmio_ioread8(struct regmap_mmio_context *ctx,
260                                         unsigned int reg)
261 {
262         return ioread8(ctx->regs + reg);
263 }
264
265 static unsigned int regmap_mmio_read16le(struct regmap_mmio_context *ctx,
266                                          unsigned int reg)
267 {
268         return readw(ctx->regs + reg);
269 }
270
271 static unsigned int regmap_mmio_read16le_relaxed(struct regmap_mmio_context *ctx,
272                                                  unsigned int reg)
273 {
274         return readw_relaxed(ctx->regs + reg);
275 }
276
277 static unsigned int regmap_mmio_ioread16le(struct regmap_mmio_context *ctx,
278                                            unsigned int reg)
279 {
280         return ioread16(ctx->regs + reg);
281 }
282
283 static unsigned int regmap_mmio_read16be(struct regmap_mmio_context *ctx,
284                                          unsigned int reg)
285 {
286         return swab16(readw(ctx->regs + reg));
287 }
288
289 static unsigned int regmap_mmio_ioread16be(struct regmap_mmio_context *ctx,
290                                            unsigned int reg)
291 {
292         return ioread16be(ctx->regs + reg);
293 }
294
295 static unsigned int regmap_mmio_read32le(struct regmap_mmio_context *ctx,
296                                          unsigned int reg)
297 {
298         return readl(ctx->regs + reg);
299 }
300
301 static unsigned int regmap_mmio_read32le_relaxed(struct regmap_mmio_context *ctx,
302                                                  unsigned int reg)
303 {
304         return readl_relaxed(ctx->regs + reg);
305 }
306
307 static unsigned int regmap_mmio_ioread32le(struct regmap_mmio_context *ctx,
308                                            unsigned int reg)
309 {
310         return ioread32(ctx->regs + reg);
311 }
312
313 static unsigned int regmap_mmio_read32be(struct regmap_mmio_context *ctx,
314                                          unsigned int reg)
315 {
316         return swab32(readl(ctx->regs + reg));
317 }
318
319 static unsigned int regmap_mmio_ioread32be(struct regmap_mmio_context *ctx,
320                                            unsigned int reg)
321 {
322         return ioread32be(ctx->regs + reg);
323 }
324
325 static int regmap_mmio_read(void *context, unsigned int reg, unsigned int *val)
326 {
327         struct regmap_mmio_context *ctx = context;
328         int ret;
329
330         if (!IS_ERR(ctx->clk)) {
331                 ret = clk_enable(ctx->clk);
332                 if (ret < 0)
333                         return ret;
334         }
335
336         *val = ctx->reg_read(ctx, reg);
337
338         if (!IS_ERR(ctx->clk))
339                 clk_disable(ctx->clk);
340
341         return 0;
342 }
343
344 static int regmap_mmio_noinc_read(void *context, unsigned int reg,
345                                   void *val, size_t val_count)
346 {
347         struct regmap_mmio_context *ctx = context;
348         int ret = 0;
349
350         if (!IS_ERR(ctx->clk)) {
351                 ret = clk_enable(ctx->clk);
352                 if (ret < 0)
353                         return ret;
354         }
355
356         switch (ctx->val_bytes) {
357         case 1:
358                 readsb(ctx->regs + reg, (u8 *)val, val_count);
359                 break;
360         case 2:
361                 readsw(ctx->regs + reg, (u16 *)val, val_count);
362                 break;
363         case 4:
364                 readsl(ctx->regs + reg, (u32 *)val, val_count);
365                 break;
366 #ifdef CONFIG_64BIT
367         case 8:
368                 readsq(ctx->regs + reg, (u64 *)val, val_count);
369                 break;
370 #endif
371         default:
372                 ret = -EINVAL;
373                 goto out_clk;
374         }
375
376         /*
377          * There are no native, assembly-optimized write single register
378          * operations for big endian, so fall back to emulation if this
379          * is needed. (Single bytes are fine, they are not affected by
380          * endianness.)
381          */
382         if (ctx->big_endian && (ctx->val_bytes > 1)) {
383                 switch (ctx->val_bytes) {
384                 case 2:
385                         swab16_array(val, val_count);
386                         break;
387                 case 4:
388                         swab32_array(val, val_count);
389                         break;
390 #ifdef CONFIG_64BIT
391                 case 8:
392                         swab64_array(val, val_count);
393                         break;
394 #endif
395                 default:
396                         ret = -EINVAL;
397                         break;
398                 }
399         }
400
401 out_clk:
402         if (!IS_ERR(ctx->clk))
403                 clk_disable(ctx->clk);
404
405         return ret;
406 }
407
408
409 static void regmap_mmio_free_context(void *context)
410 {
411         struct regmap_mmio_context *ctx = context;
412
413         if (!IS_ERR(ctx->clk)) {
414                 clk_unprepare(ctx->clk);
415                 if (!ctx->attached_clk)
416                         clk_put(ctx->clk);
417         }
418         kfree(context);
419 }
420
421 static const struct regmap_bus regmap_mmio = {
422         .fast_io = true,
423         .reg_write = regmap_mmio_write,
424         .reg_read = regmap_mmio_read,
425         .reg_noinc_write = regmap_mmio_noinc_write,
426         .reg_noinc_read = regmap_mmio_noinc_read,
427         .free_context = regmap_mmio_free_context,
428         .val_format_endian_default = REGMAP_ENDIAN_LITTLE,
429 };
430
431 static struct regmap_mmio_context *regmap_mmio_gen_context(struct device *dev,
432                                         const char *clk_id,
433                                         void __iomem *regs,
434                                         const struct regmap_config *config)
435 {
436         struct regmap_mmio_context *ctx;
437         int min_stride;
438         int ret;
439
440         ret = regmap_mmio_regbits_check(config->reg_bits);
441         if (ret)
442                 return ERR_PTR(ret);
443
444         if (config->pad_bits)
445                 return ERR_PTR(-EINVAL);
446
447         min_stride = regmap_mmio_get_min_stride(config->val_bits);
448         if (min_stride < 0)
449                 return ERR_PTR(min_stride);
450
451         if (config->reg_stride && config->reg_stride < min_stride)
452                 return ERR_PTR(-EINVAL);
453
454         if (config->use_relaxed_mmio && config->io_port)
455                 return ERR_PTR(-EINVAL);
456
457         ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
458         if (!ctx)
459                 return ERR_PTR(-ENOMEM);
460
461         ctx->regs = regs;
462         ctx->val_bytes = config->val_bits / 8;
463         ctx->clk = ERR_PTR(-ENODEV);
464
465         switch (regmap_get_val_endian(dev, &regmap_mmio, config)) {
466         case REGMAP_ENDIAN_DEFAULT:
467         case REGMAP_ENDIAN_LITTLE:
468 #ifdef __LITTLE_ENDIAN
469         case REGMAP_ENDIAN_NATIVE:
470 #endif
471                 switch (config->val_bits) {
472                 case 8:
473                         if (config->io_port) {
474                                 ctx->reg_read = regmap_mmio_ioread8;
475                                 ctx->reg_write = regmap_mmio_iowrite8;
476                         } else if (config->use_relaxed_mmio) {
477                                 ctx->reg_read = regmap_mmio_read8_relaxed;
478                                 ctx->reg_write = regmap_mmio_write8_relaxed;
479                         } else {
480                                 ctx->reg_read = regmap_mmio_read8;
481                                 ctx->reg_write = regmap_mmio_write8;
482                         }
483                         break;
484                 case 16:
485                         if (config->io_port) {
486                                 ctx->reg_read = regmap_mmio_ioread16le;
487                                 ctx->reg_write = regmap_mmio_iowrite16le;
488                         } else if (config->use_relaxed_mmio) {
489                                 ctx->reg_read = regmap_mmio_read16le_relaxed;
490                                 ctx->reg_write = regmap_mmio_write16le_relaxed;
491                         } else {
492                                 ctx->reg_read = regmap_mmio_read16le;
493                                 ctx->reg_write = regmap_mmio_write16le;
494                         }
495                         break;
496                 case 32:
497                         if (config->io_port) {
498                                 ctx->reg_read = regmap_mmio_ioread32le;
499                                 ctx->reg_write = regmap_mmio_iowrite32le;
500                         } else if (config->use_relaxed_mmio) {
501                                 ctx->reg_read = regmap_mmio_read32le_relaxed;
502                                 ctx->reg_write = regmap_mmio_write32le_relaxed;
503                         } else {
504                                 ctx->reg_read = regmap_mmio_read32le;
505                                 ctx->reg_write = regmap_mmio_write32le;
506                         }
507                         break;
508                 default:
509                         ret = -EINVAL;
510                         goto err_free;
511                 }
512                 break;
513         case REGMAP_ENDIAN_BIG:
514 #ifdef __BIG_ENDIAN
515         case REGMAP_ENDIAN_NATIVE:
516 #endif
517                 ctx->big_endian = true;
518                 switch (config->val_bits) {
519                 case 8:
520                         if (config->io_port) {
521                                 ctx->reg_read = regmap_mmio_ioread8;
522                                 ctx->reg_write = regmap_mmio_iowrite8;
523                         } else {
524                                 ctx->reg_read = regmap_mmio_read8;
525                                 ctx->reg_write = regmap_mmio_write8;
526                         }
527                         break;
528                 case 16:
529                         if (config->io_port) {
530                                 ctx->reg_read = regmap_mmio_ioread16be;
531                                 ctx->reg_write = regmap_mmio_iowrite16be;
532                         } else {
533                                 ctx->reg_read = regmap_mmio_read16be;
534                                 ctx->reg_write = regmap_mmio_write16be;
535                         }
536                         break;
537                 case 32:
538                         if (config->io_port) {
539                                 ctx->reg_read = regmap_mmio_ioread32be;
540                                 ctx->reg_write = regmap_mmio_iowrite32be;
541                         } else {
542                                 ctx->reg_read = regmap_mmio_read32be;
543                                 ctx->reg_write = regmap_mmio_write32be;
544                         }
545                         break;
546                 default:
547                         ret = -EINVAL;
548                         goto err_free;
549                 }
550                 break;
551         default:
552                 ret = -EINVAL;
553                 goto err_free;
554         }
555
556         if (clk_id == NULL)
557                 return ctx;
558
559         ctx->clk = clk_get(dev, clk_id);
560         if (IS_ERR(ctx->clk)) {
561                 ret = PTR_ERR(ctx->clk);
562                 goto err_free;
563         }
564
565         ret = clk_prepare(ctx->clk);
566         if (ret < 0) {
567                 clk_put(ctx->clk);
568                 goto err_free;
569         }
570
571         return ctx;
572
573 err_free:
574         kfree(ctx);
575
576         return ERR_PTR(ret);
577 }
578
579 struct regmap *__regmap_init_mmio_clk(struct device *dev, const char *clk_id,
580                                       void __iomem *regs,
581                                       const struct regmap_config *config,
582                                       struct lock_class_key *lock_key,
583                                       const char *lock_name)
584 {
585         struct regmap_mmio_context *ctx;
586
587         ctx = regmap_mmio_gen_context(dev, clk_id, regs, config);
588         if (IS_ERR(ctx))
589                 return ERR_CAST(ctx);
590
591         return __regmap_init(dev, &regmap_mmio, ctx, config,
592                              lock_key, lock_name);
593 }
594 EXPORT_SYMBOL_GPL(__regmap_init_mmio_clk);
595
596 struct regmap *__devm_regmap_init_mmio_clk(struct device *dev,
597                                            const char *clk_id,
598                                            void __iomem *regs,
599                                            const struct regmap_config *config,
600                                            struct lock_class_key *lock_key,
601                                            const char *lock_name)
602 {
603         struct regmap_mmio_context *ctx;
604
605         ctx = regmap_mmio_gen_context(dev, clk_id, regs, config);
606         if (IS_ERR(ctx))
607                 return ERR_CAST(ctx);
608
609         return __devm_regmap_init(dev, &regmap_mmio, ctx, config,
610                                   lock_key, lock_name);
611 }
612 EXPORT_SYMBOL_GPL(__devm_regmap_init_mmio_clk);
613
614 int regmap_mmio_attach_clk(struct regmap *map, struct clk *clk)
615 {
616         struct regmap_mmio_context *ctx = map->bus_context;
617
618         ctx->clk = clk;
619         ctx->attached_clk = true;
620
621         return clk_prepare(ctx->clk);
622 }
623 EXPORT_SYMBOL_GPL(regmap_mmio_attach_clk);
624
625 void regmap_mmio_detach_clk(struct regmap *map)
626 {
627         struct regmap_mmio_context *ctx = map->bus_context;
628
629         clk_unprepare(ctx->clk);
630
631         ctx->attached_clk = false;
632         ctx->clk = NULL;
633 }
634 EXPORT_SYMBOL_GPL(regmap_mmio_detach_clk);
635
636 MODULE_LICENSE("GPL v2");