GNU Linux-libre 4.14.303-gnu1
[releases.git] / drivers / base / regmap / regmap-mmio.c
1 /*
2  * Register map access API - MMIO support
3  *
4  * Copyright (c) 2012, NVIDIA CORPORATION.  All rights reserved.
5  *
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms and conditions of the GNU General Public License,
8  * version 2, as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
13  * more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18
19 #include <linux/clk.h>
20 #include <linux/err.h>
21 #include <linux/io.h>
22 #include <linux/module.h>
23 #include <linux/regmap.h>
24 #include <linux/slab.h>
25
26 #include "internal.h"
27
28 struct regmap_mmio_context {
29         void __iomem *regs;
30         unsigned val_bytes;
31         struct clk *clk;
32
33         void (*reg_write)(struct regmap_mmio_context *ctx,
34                           unsigned int reg, unsigned int val);
35         unsigned int (*reg_read)(struct regmap_mmio_context *ctx,
36                                  unsigned int reg);
37 };
38
39 static int regmap_mmio_regbits_check(size_t reg_bits)
40 {
41         switch (reg_bits) {
42         case 8:
43         case 16:
44         case 32:
45 #ifdef CONFIG_64BIT
46         case 64:
47 #endif
48                 return 0;
49         default:
50                 return -EINVAL;
51         }
52 }
53
54 static int regmap_mmio_get_min_stride(size_t val_bits)
55 {
56         int min_stride;
57
58         switch (val_bits) {
59         case 8:
60                 /* The core treats 0 as 1 */
61                 min_stride = 0;
62                 return 0;
63         case 16:
64                 min_stride = 2;
65                 break;
66         case 32:
67                 min_stride = 4;
68                 break;
69 #ifdef CONFIG_64BIT
70         case 64:
71                 min_stride = 8;
72                 break;
73 #endif
74         default:
75                 return -EINVAL;
76         }
77
78         return min_stride;
79 }
80
81 static void regmap_mmio_write8(struct regmap_mmio_context *ctx,
82                                 unsigned int reg,
83                                 unsigned int val)
84 {
85         writeb(val, ctx->regs + reg);
86 }
87
88 static void regmap_mmio_write16le(struct regmap_mmio_context *ctx,
89                                   unsigned int reg,
90                                   unsigned int val)
91 {
92         writew(val, ctx->regs + reg);
93 }
94
95 static void regmap_mmio_write16be(struct regmap_mmio_context *ctx,
96                                   unsigned int reg,
97                                   unsigned int val)
98 {
99         iowrite16be(val, ctx->regs + reg);
100 }
101
102 static void regmap_mmio_write32le(struct regmap_mmio_context *ctx,
103                                   unsigned int reg,
104                                   unsigned int val)
105 {
106         writel(val, ctx->regs + reg);
107 }
108
109 static void regmap_mmio_write32be(struct regmap_mmio_context *ctx,
110                                   unsigned int reg,
111                                   unsigned int val)
112 {
113         iowrite32be(val, ctx->regs + reg);
114 }
115
116 #ifdef CONFIG_64BIT
117 static void regmap_mmio_write64le(struct regmap_mmio_context *ctx,
118                                   unsigned int reg,
119                                   unsigned int val)
120 {
121         writeq(val, ctx->regs + reg);
122 }
123 #endif
124
125 static int regmap_mmio_write(void *context, unsigned int reg, unsigned int val)
126 {
127         struct regmap_mmio_context *ctx = context;
128         int ret;
129
130         if (!IS_ERR(ctx->clk)) {
131                 ret = clk_enable(ctx->clk);
132                 if (ret < 0)
133                         return ret;
134         }
135
136         ctx->reg_write(ctx, reg, val);
137
138         if (!IS_ERR(ctx->clk))
139                 clk_disable(ctx->clk);
140
141         return 0;
142 }
143
144 static unsigned int regmap_mmio_read8(struct regmap_mmio_context *ctx,
145                                       unsigned int reg)
146 {
147         return readb(ctx->regs + reg);
148 }
149
150 static unsigned int regmap_mmio_read16le(struct regmap_mmio_context *ctx,
151                                          unsigned int reg)
152 {
153         return readw(ctx->regs + reg);
154 }
155
156 static unsigned int regmap_mmio_read16be(struct regmap_mmio_context *ctx,
157                                          unsigned int reg)
158 {
159         return ioread16be(ctx->regs + reg);
160 }
161
162 static unsigned int regmap_mmio_read32le(struct regmap_mmio_context *ctx,
163                                          unsigned int reg)
164 {
165         return readl(ctx->regs + reg);
166 }
167
168 static unsigned int regmap_mmio_read32be(struct regmap_mmio_context *ctx,
169                                          unsigned int reg)
170 {
171         return ioread32be(ctx->regs + reg);
172 }
173
174 #ifdef CONFIG_64BIT
175 static unsigned int regmap_mmio_read64le(struct regmap_mmio_context *ctx,
176                                          unsigned int reg)
177 {
178         return readq(ctx->regs + reg);
179 }
180 #endif
181
182 static int regmap_mmio_read(void *context, unsigned int reg, unsigned int *val)
183 {
184         struct regmap_mmio_context *ctx = context;
185         int ret;
186
187         if (!IS_ERR(ctx->clk)) {
188                 ret = clk_enable(ctx->clk);
189                 if (ret < 0)
190                         return ret;
191         }
192
193         *val = ctx->reg_read(ctx, reg);
194
195         if (!IS_ERR(ctx->clk))
196                 clk_disable(ctx->clk);
197
198         return 0;
199 }
200
201 static void regmap_mmio_free_context(void *context)
202 {
203         struct regmap_mmio_context *ctx = context;
204
205         if (!IS_ERR(ctx->clk)) {
206                 clk_unprepare(ctx->clk);
207                 clk_put(ctx->clk);
208         }
209         kfree(context);
210 }
211
212 static const struct regmap_bus regmap_mmio = {
213         .fast_io = true,
214         .reg_write = regmap_mmio_write,
215         .reg_read = regmap_mmio_read,
216         .free_context = regmap_mmio_free_context,
217         .val_format_endian_default = REGMAP_ENDIAN_LITTLE,
218 };
219
220 static struct regmap_mmio_context *regmap_mmio_gen_context(struct device *dev,
221                                         const char *clk_id,
222                                         void __iomem *regs,
223                                         const struct regmap_config *config)
224 {
225         struct regmap_mmio_context *ctx;
226         int min_stride;
227         int ret;
228
229         ret = regmap_mmio_regbits_check(config->reg_bits);
230         if (ret)
231                 return ERR_PTR(ret);
232
233         if (config->pad_bits)
234                 return ERR_PTR(-EINVAL);
235
236         min_stride = regmap_mmio_get_min_stride(config->val_bits);
237         if (min_stride < 0)
238                 return ERR_PTR(min_stride);
239
240         if (config->reg_stride < min_stride)
241                 return ERR_PTR(-EINVAL);
242
243         ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
244         if (!ctx)
245                 return ERR_PTR(-ENOMEM);
246
247         ctx->regs = regs;
248         ctx->val_bytes = config->val_bits / 8;
249         ctx->clk = ERR_PTR(-ENODEV);
250
251         switch (regmap_get_val_endian(dev, &regmap_mmio, config)) {
252         case REGMAP_ENDIAN_DEFAULT:
253         case REGMAP_ENDIAN_LITTLE:
254 #ifdef __LITTLE_ENDIAN
255         case REGMAP_ENDIAN_NATIVE:
256 #endif
257                 switch (config->val_bits) {
258                 case 8:
259                         ctx->reg_read = regmap_mmio_read8;
260                         ctx->reg_write = regmap_mmio_write8;
261                         break;
262                 case 16:
263                         ctx->reg_read = regmap_mmio_read16le;
264                         ctx->reg_write = regmap_mmio_write16le;
265                         break;
266                 case 32:
267                         ctx->reg_read = regmap_mmio_read32le;
268                         ctx->reg_write = regmap_mmio_write32le;
269                         break;
270 #ifdef CONFIG_64BIT
271                 case 64:
272                         ctx->reg_read = regmap_mmio_read64le;
273                         ctx->reg_write = regmap_mmio_write64le;
274                         break;
275 #endif
276                 default:
277                         ret = -EINVAL;
278                         goto err_free;
279                 }
280                 break;
281         case REGMAP_ENDIAN_BIG:
282 #ifdef __BIG_ENDIAN
283         case REGMAP_ENDIAN_NATIVE:
284 #endif
285                 switch (config->val_bits) {
286                 case 8:
287                         ctx->reg_read = regmap_mmio_read8;
288                         ctx->reg_write = regmap_mmio_write8;
289                         break;
290                 case 16:
291                         ctx->reg_read = regmap_mmio_read16be;
292                         ctx->reg_write = regmap_mmio_write16be;
293                         break;
294                 case 32:
295                         ctx->reg_read = regmap_mmio_read32be;
296                         ctx->reg_write = regmap_mmio_write32be;
297                         break;
298                 default:
299                         ret = -EINVAL;
300                         goto err_free;
301                 }
302                 break;
303         default:
304                 ret = -EINVAL;
305                 goto err_free;
306         }
307
308         if (clk_id == NULL)
309                 return ctx;
310
311         ctx->clk = clk_get(dev, clk_id);
312         if (IS_ERR(ctx->clk)) {
313                 ret = PTR_ERR(ctx->clk);
314                 goto err_free;
315         }
316
317         ret = clk_prepare(ctx->clk);
318         if (ret < 0) {
319                 clk_put(ctx->clk);
320                 goto err_free;
321         }
322
323         return ctx;
324
325 err_free:
326         kfree(ctx);
327
328         return ERR_PTR(ret);
329 }
330
331 struct regmap *__regmap_init_mmio_clk(struct device *dev, const char *clk_id,
332                                       void __iomem *regs,
333                                       const struct regmap_config *config,
334                                       struct lock_class_key *lock_key,
335                                       const char *lock_name)
336 {
337         struct regmap_mmio_context *ctx;
338
339         ctx = regmap_mmio_gen_context(dev, clk_id, regs, config);
340         if (IS_ERR(ctx))
341                 return ERR_CAST(ctx);
342
343         return __regmap_init(dev, &regmap_mmio, ctx, config,
344                              lock_key, lock_name);
345 }
346 EXPORT_SYMBOL_GPL(__regmap_init_mmio_clk);
347
348 struct regmap *__devm_regmap_init_mmio_clk(struct device *dev,
349                                            const char *clk_id,
350                                            void __iomem *regs,
351                                            const struct regmap_config *config,
352                                            struct lock_class_key *lock_key,
353                                            const char *lock_name)
354 {
355         struct regmap_mmio_context *ctx;
356
357         ctx = regmap_mmio_gen_context(dev, clk_id, regs, config);
358         if (IS_ERR(ctx))
359                 return ERR_CAST(ctx);
360
361         return __devm_regmap_init(dev, &regmap_mmio, ctx, config,
362                                   lock_key, lock_name);
363 }
364 EXPORT_SYMBOL_GPL(__devm_regmap_init_mmio_clk);
365
366 MODULE_LICENSE("GPL v2");