2 * Register map access API - MMIO support
4 * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
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.
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
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/>.
19 #include <linux/clk.h>
20 #include <linux/err.h>
21 #include <linux/init.h>
23 #include <linux/module.h>
24 #include <linux/regmap.h>
25 #include <linux/slab.h>
27 struct regmap_mmio_context
{
33 static int regmap_mmio_gather_write(void *context
,
34 const void *reg
, size_t reg_size
,
35 const void *val
, size_t val_size
)
37 struct regmap_mmio_context
*ctx
= context
;
41 BUG_ON(reg_size
!= 4);
43 if (!IS_ERR(ctx
->clk
)) {
44 ret
= clk_enable(ctx
->clk
);
52 switch (ctx
->val_bytes
) {
54 writeb(*(u8
*)val
, ctx
->regs
+ offset
);
57 writew(*(u16
*)val
, ctx
->regs
+ offset
);
60 writel(*(u32
*)val
, ctx
->regs
+ offset
);
64 writeq(*(u64
*)val
, ctx
->regs
+ offset
);
68 /* Should be caught by regmap_mmio_check_config */
71 val_size
-= ctx
->val_bytes
;
72 val
+= ctx
->val_bytes
;
73 offset
+= ctx
->val_bytes
;
76 if (!IS_ERR(ctx
->clk
))
77 clk_disable(ctx
->clk
);
82 static int regmap_mmio_write(void *context
, const void *data
, size_t count
)
86 return regmap_mmio_gather_write(context
, data
, 4, data
+ 4, count
- 4);
89 static int regmap_mmio_read(void *context
,
90 const void *reg
, size_t reg_size
,
91 void *val
, size_t val_size
)
93 struct regmap_mmio_context
*ctx
= context
;
97 BUG_ON(reg_size
!= 4);
99 if (!IS_ERR(ctx
->clk
)) {
100 ret
= clk_enable(ctx
->clk
);
105 offset
= *(u32
*)reg
;
108 switch (ctx
->val_bytes
) {
110 *(u8
*)val
= readb(ctx
->regs
+ offset
);
113 *(u16
*)val
= readw(ctx
->regs
+ offset
);
116 *(u32
*)val
= readl(ctx
->regs
+ offset
);
120 *(u64
*)val
= readq(ctx
->regs
+ offset
);
124 /* Should be caught by regmap_mmio_check_config */
127 val_size
-= ctx
->val_bytes
;
128 val
+= ctx
->val_bytes
;
129 offset
+= ctx
->val_bytes
;
132 if (!IS_ERR(ctx
->clk
))
133 clk_disable(ctx
->clk
);
138 static void regmap_mmio_free_context(void *context
)
140 struct regmap_mmio_context
*ctx
= context
;
142 if (!IS_ERR(ctx
->clk
)) {
143 clk_unprepare(ctx
->clk
);
149 static struct regmap_bus regmap_mmio
= {
151 .write
= regmap_mmio_write
,
152 .gather_write
= regmap_mmio_gather_write
,
153 .read
= regmap_mmio_read
,
154 .free_context
= regmap_mmio_free_context
,
155 .reg_format_endian_default
= REGMAP_ENDIAN_NATIVE
,
156 .val_format_endian_default
= REGMAP_ENDIAN_NATIVE
,
159 static struct regmap_mmio_context
*regmap_mmio_gen_context(struct device
*dev
,
162 const struct regmap_config
*config
)
164 struct regmap_mmio_context
*ctx
;
168 if (config
->reg_bits
!= 32)
169 return ERR_PTR(-EINVAL
);
171 if (config
->pad_bits
)
172 return ERR_PTR(-EINVAL
);
174 switch (config
->val_bits
) {
176 /* The core treats 0 as 1 */
192 return ERR_PTR(-EINVAL
);
195 if (config
->reg_stride
< min_stride
)
196 return ERR_PTR(-EINVAL
);
198 switch (config
->reg_format_endian
) {
199 case REGMAP_ENDIAN_DEFAULT
:
200 case REGMAP_ENDIAN_NATIVE
:
203 return ERR_PTR(-EINVAL
);
206 ctx
= kzalloc(sizeof(*ctx
), GFP_KERNEL
);
208 return ERR_PTR(-ENOMEM
);
211 ctx
->val_bytes
= config
->val_bits
/ 8;
212 ctx
->clk
= ERR_PTR(-ENODEV
);
217 ctx
->clk
= clk_get(dev
, clk_id
);
218 if (IS_ERR(ctx
->clk
)) {
219 ret
= PTR_ERR(ctx
->clk
);
223 ret
= clk_prepare(ctx
->clk
);
238 * regmap_init_mmio_clk(): Initialise register map with register clock
240 * @dev: Device that will be interacted with
241 * @clk_id: register clock consumer ID
242 * @regs: Pointer to memory-mapped IO region
243 * @config: Configuration for register map
245 * The return value will be an ERR_PTR() on error or a valid pointer to
248 struct regmap
*regmap_init_mmio_clk(struct device
*dev
, const char *clk_id
,
250 const struct regmap_config
*config
)
252 struct regmap_mmio_context
*ctx
;
254 ctx
= regmap_mmio_gen_context(dev
, clk_id
, regs
, config
);
256 return ERR_CAST(ctx
);
258 return regmap_init(dev
, ®map_mmio
, ctx
, config
);
260 EXPORT_SYMBOL_GPL(regmap_init_mmio_clk
);
263 * devm_regmap_init_mmio_clk(): Initialise managed register map with clock
265 * @dev: Device that will be interacted with
266 * @clk_id: register clock consumer ID
267 * @regs: Pointer to memory-mapped IO region
268 * @config: Configuration for register map
270 * The return value will be an ERR_PTR() on error or a valid pointer
271 * to a struct regmap. The regmap will be automatically freed by the
272 * device management code.
274 struct regmap
*devm_regmap_init_mmio_clk(struct device
*dev
, const char *clk_id
,
276 const struct regmap_config
*config
)
278 struct regmap_mmio_context
*ctx
;
280 ctx
= regmap_mmio_gen_context(dev
, clk_id
, regs
, config
);
282 return ERR_CAST(ctx
);
284 return devm_regmap_init(dev
, ®map_mmio
, ctx
, config
);
286 EXPORT_SYMBOL_GPL(devm_regmap_init_mmio_clk
);
288 MODULE_LICENSE("GPL v2");