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
{
23 void (*reg_write
)(struct regmap_mmio_context
*ctx
,
24 unsigned int reg
, unsigned int val
);
25 unsigned int (*reg_read
)(struct regmap_mmio_context
*ctx
,
29 static int regmap_mmio_regbits_check(size_t reg_bits
)
44 static int regmap_mmio_get_min_stride(size_t val_bits
)
50 /* The core treats 0 as 1 */
71 static void regmap_mmio_write8(struct regmap_mmio_context
*ctx
,
75 writeb(val
, ctx
->regs
+ reg
);
78 static void regmap_mmio_write16le(struct regmap_mmio_context
*ctx
,
82 writew(val
, ctx
->regs
+ reg
);
85 static void regmap_mmio_write16be(struct regmap_mmio_context
*ctx
,
89 iowrite16be(val
, ctx
->regs
+ reg
);
92 static void regmap_mmio_write32le(struct regmap_mmio_context
*ctx
,
96 writel(val
, ctx
->regs
+ reg
);
99 static void regmap_mmio_write32be(struct regmap_mmio_context
*ctx
,
103 iowrite32be(val
, ctx
->regs
+ reg
);
107 static void regmap_mmio_write64le(struct regmap_mmio_context
*ctx
,
111 writeq(val
, ctx
->regs
+ reg
);
115 static int regmap_mmio_write(void *context
, unsigned int reg
, unsigned int val
)
117 struct regmap_mmio_context
*ctx
= context
;
120 if (!IS_ERR(ctx
->clk
)) {
121 ret
= clk_enable(ctx
->clk
);
126 ctx
->reg_write(ctx
, reg
, val
);
128 if (!IS_ERR(ctx
->clk
))
129 clk_disable(ctx
->clk
);
134 static unsigned int regmap_mmio_read8(struct regmap_mmio_context
*ctx
,
137 return readb(ctx
->regs
+ reg
);
140 static unsigned int regmap_mmio_read16le(struct regmap_mmio_context
*ctx
,
143 return readw(ctx
->regs
+ reg
);
146 static unsigned int regmap_mmio_read16be(struct regmap_mmio_context
*ctx
,
149 return ioread16be(ctx
->regs
+ reg
);
152 static unsigned int regmap_mmio_read32le(struct regmap_mmio_context
*ctx
,
155 return readl(ctx
->regs
+ reg
);
158 static unsigned int regmap_mmio_read32be(struct regmap_mmio_context
*ctx
,
161 return ioread32be(ctx
->regs
+ reg
);
165 static unsigned int regmap_mmio_read64le(struct regmap_mmio_context
*ctx
,
168 return readq(ctx
->regs
+ reg
);
172 static int regmap_mmio_read(void *context
, unsigned int reg
, unsigned int *val
)
174 struct regmap_mmio_context
*ctx
= context
;
177 if (!IS_ERR(ctx
->clk
)) {
178 ret
= clk_enable(ctx
->clk
);
183 *val
= ctx
->reg_read(ctx
, reg
);
185 if (!IS_ERR(ctx
->clk
))
186 clk_disable(ctx
->clk
);
191 static void regmap_mmio_free_context(void *context
)
193 struct regmap_mmio_context
*ctx
= context
;
195 if (!IS_ERR(ctx
->clk
)) {
196 clk_unprepare(ctx
->clk
);
197 if (!ctx
->attached_clk
)
203 static const struct regmap_bus regmap_mmio
= {
205 .reg_write
= regmap_mmio_write
,
206 .reg_read
= regmap_mmio_read
,
207 .free_context
= regmap_mmio_free_context
,
208 .val_format_endian_default
= REGMAP_ENDIAN_LITTLE
,
211 static struct regmap_mmio_context
*regmap_mmio_gen_context(struct device
*dev
,
214 const struct regmap_config
*config
)
216 struct regmap_mmio_context
*ctx
;
220 ret
= regmap_mmio_regbits_check(config
->reg_bits
);
224 if (config
->pad_bits
)
225 return ERR_PTR(-EINVAL
);
227 min_stride
= regmap_mmio_get_min_stride(config
->val_bits
);
229 return ERR_PTR(min_stride
);
231 if (config
->reg_stride
< min_stride
)
232 return ERR_PTR(-EINVAL
);
234 ctx
= kzalloc(sizeof(*ctx
), GFP_KERNEL
);
236 return ERR_PTR(-ENOMEM
);
239 ctx
->val_bytes
= config
->val_bits
/ 8;
240 ctx
->clk
= ERR_PTR(-ENODEV
);
242 switch (regmap_get_val_endian(dev
, ®map_mmio
, config
)) {
243 case REGMAP_ENDIAN_DEFAULT
:
244 case REGMAP_ENDIAN_LITTLE
:
245 #ifdef __LITTLE_ENDIAN
246 case REGMAP_ENDIAN_NATIVE
:
248 switch (config
->val_bits
) {
250 ctx
->reg_read
= regmap_mmio_read8
;
251 ctx
->reg_write
= regmap_mmio_write8
;
254 ctx
->reg_read
= regmap_mmio_read16le
;
255 ctx
->reg_write
= regmap_mmio_write16le
;
258 ctx
->reg_read
= regmap_mmio_read32le
;
259 ctx
->reg_write
= regmap_mmio_write32le
;
263 ctx
->reg_read
= regmap_mmio_read64le
;
264 ctx
->reg_write
= regmap_mmio_write64le
;
272 case REGMAP_ENDIAN_BIG
:
274 case REGMAP_ENDIAN_NATIVE
:
276 switch (config
->val_bits
) {
278 ctx
->reg_read
= regmap_mmio_read8
;
279 ctx
->reg_write
= regmap_mmio_write8
;
282 ctx
->reg_read
= regmap_mmio_read16be
;
283 ctx
->reg_write
= regmap_mmio_write16be
;
286 ctx
->reg_read
= regmap_mmio_read32be
;
287 ctx
->reg_write
= regmap_mmio_write32be
;
302 ctx
->clk
= clk_get(dev
, clk_id
);
303 if (IS_ERR(ctx
->clk
)) {
304 ret
= PTR_ERR(ctx
->clk
);
308 ret
= clk_prepare(ctx
->clk
);
322 struct regmap
*__regmap_init_mmio_clk(struct device
*dev
, const char *clk_id
,
324 const struct regmap_config
*config
,
325 struct lock_class_key
*lock_key
,
326 const char *lock_name
)
328 struct regmap_mmio_context
*ctx
;
330 ctx
= regmap_mmio_gen_context(dev
, clk_id
, regs
, config
);
332 return ERR_CAST(ctx
);
334 return __regmap_init(dev
, ®map_mmio
, ctx
, config
,
335 lock_key
, lock_name
);
337 EXPORT_SYMBOL_GPL(__regmap_init_mmio_clk
);
339 struct regmap
*__devm_regmap_init_mmio_clk(struct device
*dev
,
342 const struct regmap_config
*config
,
343 struct lock_class_key
*lock_key
,
344 const char *lock_name
)
346 struct regmap_mmio_context
*ctx
;
348 ctx
= regmap_mmio_gen_context(dev
, clk_id
, regs
, config
);
350 return ERR_CAST(ctx
);
352 return __devm_regmap_init(dev
, ®map_mmio
, ctx
, config
,
353 lock_key
, lock_name
);
355 EXPORT_SYMBOL_GPL(__devm_regmap_init_mmio_clk
);
357 int regmap_mmio_attach_clk(struct regmap
*map
, struct clk
*clk
)
359 struct regmap_mmio_context
*ctx
= map
->bus_context
;
362 ctx
->attached_clk
= true;
364 return clk_prepare(ctx
->clk
);
366 EXPORT_SYMBOL_GPL(regmap_mmio_attach_clk
);
368 void regmap_mmio_detach_clk(struct regmap
*map
)
370 struct regmap_mmio_context
*ctx
= map
->bus_context
;
372 clk_unprepare(ctx
->clk
);
374 ctx
->attached_clk
= false;
377 EXPORT_SYMBOL_GPL(regmap_mmio_detach_clk
);
379 MODULE_LICENSE("GPL v2");