1 // SPDX-License-Identifier: GPL-2.0
3 // Register map access API - MMIO support
5 // Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
10 #include <linux/module.h>
11 #include <linux/regmap.h>
12 #include <linux/slab.h>
16 struct regmap_mmio_context
{
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
,
30 static int regmap_mmio_regbits_check(size_t reg_bits
)
45 static int regmap_mmio_get_min_stride(size_t val_bits
)
51 /* The core treats 0 as 1 */
72 static void regmap_mmio_write8(struct regmap_mmio_context
*ctx
,
76 writeb(val
, ctx
->regs
+ reg
);
79 static void regmap_mmio_write8_relaxed(struct regmap_mmio_context
*ctx
,
83 writeb_relaxed(val
, ctx
->regs
+ reg
);
86 static void regmap_mmio_write16le(struct regmap_mmio_context
*ctx
,
90 writew(val
, ctx
->regs
+ reg
);
93 static void regmap_mmio_write16le_relaxed(struct regmap_mmio_context
*ctx
,
97 writew_relaxed(val
, ctx
->regs
+ reg
);
100 static void regmap_mmio_write16be(struct regmap_mmio_context
*ctx
,
104 iowrite16be(val
, ctx
->regs
+ reg
);
107 static void regmap_mmio_write32le(struct regmap_mmio_context
*ctx
,
111 writel(val
, ctx
->regs
+ reg
);
114 static void regmap_mmio_write32le_relaxed(struct regmap_mmio_context
*ctx
,
118 writel_relaxed(val
, ctx
->regs
+ reg
);
121 static void regmap_mmio_write32be(struct regmap_mmio_context
*ctx
,
125 iowrite32be(val
, ctx
->regs
+ reg
);
129 static void regmap_mmio_write64le(struct regmap_mmio_context
*ctx
,
133 writeq(val
, ctx
->regs
+ reg
);
136 static void regmap_mmio_write64le_relaxed(struct regmap_mmio_context
*ctx
,
140 writeq_relaxed(val
, ctx
->regs
+ reg
);
144 static int regmap_mmio_write(void *context
, unsigned int reg
, unsigned int val
)
146 struct regmap_mmio_context
*ctx
= context
;
149 if (!IS_ERR(ctx
->clk
)) {
150 ret
= clk_enable(ctx
->clk
);
155 ctx
->reg_write(ctx
, reg
, val
);
157 if (!IS_ERR(ctx
->clk
))
158 clk_disable(ctx
->clk
);
163 static unsigned int regmap_mmio_read8(struct regmap_mmio_context
*ctx
,
166 return readb(ctx
->regs
+ reg
);
169 static unsigned int regmap_mmio_read8_relaxed(struct regmap_mmio_context
*ctx
,
172 return readb_relaxed(ctx
->regs
+ reg
);
175 static unsigned int regmap_mmio_read16le(struct regmap_mmio_context
*ctx
,
178 return readw(ctx
->regs
+ reg
);
181 static unsigned int regmap_mmio_read16le_relaxed(struct regmap_mmio_context
*ctx
,
184 return readw_relaxed(ctx
->regs
+ reg
);
187 static unsigned int regmap_mmio_read16be(struct regmap_mmio_context
*ctx
,
190 return ioread16be(ctx
->regs
+ reg
);
193 static unsigned int regmap_mmio_read32le(struct regmap_mmio_context
*ctx
,
196 return readl(ctx
->regs
+ reg
);
199 static unsigned int regmap_mmio_read32le_relaxed(struct regmap_mmio_context
*ctx
,
202 return readl_relaxed(ctx
->regs
+ reg
);
205 static unsigned int regmap_mmio_read32be(struct regmap_mmio_context
*ctx
,
208 return ioread32be(ctx
->regs
+ reg
);
212 static unsigned int regmap_mmio_read64le(struct regmap_mmio_context
*ctx
,
215 return readq(ctx
->regs
+ reg
);
218 static unsigned int regmap_mmio_read64le_relaxed(struct regmap_mmio_context
*ctx
,
221 return readq_relaxed(ctx
->regs
+ reg
);
225 static int regmap_mmio_read(void *context
, unsigned int reg
, unsigned int *val
)
227 struct regmap_mmio_context
*ctx
= context
;
230 if (!IS_ERR(ctx
->clk
)) {
231 ret
= clk_enable(ctx
->clk
);
236 *val
= ctx
->reg_read(ctx
, reg
);
238 if (!IS_ERR(ctx
->clk
))
239 clk_disable(ctx
->clk
);
244 static void regmap_mmio_free_context(void *context
)
246 struct regmap_mmio_context
*ctx
= context
;
248 if (!IS_ERR(ctx
->clk
)) {
249 clk_unprepare(ctx
->clk
);
250 if (!ctx
->attached_clk
)
256 static const struct regmap_bus regmap_mmio
= {
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
,
264 static struct regmap_mmio_context
*regmap_mmio_gen_context(struct device
*dev
,
267 const struct regmap_config
*config
)
269 struct regmap_mmio_context
*ctx
;
273 ret
= regmap_mmio_regbits_check(config
->reg_bits
);
277 if (config
->pad_bits
)
278 return ERR_PTR(-EINVAL
);
280 min_stride
= regmap_mmio_get_min_stride(config
->val_bits
);
282 return ERR_PTR(min_stride
);
284 if (config
->reg_stride
< min_stride
)
285 return ERR_PTR(-EINVAL
);
287 ctx
= kzalloc(sizeof(*ctx
), GFP_KERNEL
);
289 return ERR_PTR(-ENOMEM
);
292 ctx
->val_bytes
= config
->val_bits
/ 8;
293 ctx
->relaxed_mmio
= config
->use_relaxed_mmio
;
294 ctx
->clk
= ERR_PTR(-ENODEV
);
296 switch (regmap_get_val_endian(dev
, ®map_mmio
, config
)) {
297 case REGMAP_ENDIAN_DEFAULT
:
298 case REGMAP_ENDIAN_LITTLE
:
299 #ifdef __LITTLE_ENDIAN
300 case REGMAP_ENDIAN_NATIVE
:
302 switch (config
->val_bits
) {
304 if (ctx
->relaxed_mmio
) {
305 ctx
->reg_read
= regmap_mmio_read8_relaxed
;
306 ctx
->reg_write
= regmap_mmio_write8_relaxed
;
308 ctx
->reg_read
= regmap_mmio_read8
;
309 ctx
->reg_write
= regmap_mmio_write8
;
313 if (ctx
->relaxed_mmio
) {
314 ctx
->reg_read
= regmap_mmio_read16le_relaxed
;
315 ctx
->reg_write
= regmap_mmio_write16le_relaxed
;
317 ctx
->reg_read
= regmap_mmio_read16le
;
318 ctx
->reg_write
= regmap_mmio_write16le
;
322 if (ctx
->relaxed_mmio
) {
323 ctx
->reg_read
= regmap_mmio_read32le_relaxed
;
324 ctx
->reg_write
= regmap_mmio_write32le_relaxed
;
326 ctx
->reg_read
= regmap_mmio_read32le
;
327 ctx
->reg_write
= regmap_mmio_write32le
;
332 if (ctx
->relaxed_mmio
) {
333 ctx
->reg_read
= regmap_mmio_read64le_relaxed
;
334 ctx
->reg_write
= regmap_mmio_write64le_relaxed
;
336 ctx
->reg_read
= regmap_mmio_read64le
;
337 ctx
->reg_write
= regmap_mmio_write64le
;
346 case REGMAP_ENDIAN_BIG
:
348 case REGMAP_ENDIAN_NATIVE
:
350 switch (config
->val_bits
) {
352 ctx
->reg_read
= regmap_mmio_read8
;
353 ctx
->reg_write
= regmap_mmio_write8
;
356 ctx
->reg_read
= regmap_mmio_read16be
;
357 ctx
->reg_write
= regmap_mmio_write16be
;
360 ctx
->reg_read
= regmap_mmio_read32be
;
361 ctx
->reg_write
= regmap_mmio_write32be
;
376 ctx
->clk
= clk_get(dev
, clk_id
);
377 if (IS_ERR(ctx
->clk
)) {
378 ret
= PTR_ERR(ctx
->clk
);
382 ret
= clk_prepare(ctx
->clk
);
396 struct regmap
*__regmap_init_mmio_clk(struct device
*dev
, const char *clk_id
,
398 const struct regmap_config
*config
,
399 struct lock_class_key
*lock_key
,
400 const char *lock_name
)
402 struct regmap_mmio_context
*ctx
;
404 ctx
= regmap_mmio_gen_context(dev
, clk_id
, regs
, config
);
406 return ERR_CAST(ctx
);
408 return __regmap_init(dev
, ®map_mmio
, ctx
, config
,
409 lock_key
, lock_name
);
411 EXPORT_SYMBOL_GPL(__regmap_init_mmio_clk
);
413 struct regmap
*__devm_regmap_init_mmio_clk(struct device
*dev
,
416 const struct regmap_config
*config
,
417 struct lock_class_key
*lock_key
,
418 const char *lock_name
)
420 struct regmap_mmio_context
*ctx
;
422 ctx
= regmap_mmio_gen_context(dev
, clk_id
, regs
, config
);
424 return ERR_CAST(ctx
);
426 return __devm_regmap_init(dev
, ®map_mmio
, ctx
, config
,
427 lock_key
, lock_name
);
429 EXPORT_SYMBOL_GPL(__devm_regmap_init_mmio_clk
);
431 int regmap_mmio_attach_clk(struct regmap
*map
, struct clk
*clk
)
433 struct regmap_mmio_context
*ctx
= map
->bus_context
;
436 ctx
->attached_clk
= true;
438 return clk_prepare(ctx
->clk
);
440 EXPORT_SYMBOL_GPL(regmap_mmio_attach_clk
);
442 void regmap_mmio_detach_clk(struct regmap
*map
)
444 struct regmap_mmio_context
*ctx
= map
->bus_context
;
446 clk_unprepare(ctx
->clk
);
448 ctx
->attached_clk
= false;
451 EXPORT_SYMBOL_GPL(regmap_mmio_detach_clk
);
453 MODULE_LICENSE("GPL v2");