Root/
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/init.h> |
22 | #include <linux/io.h> |
23 | #include <linux/module.h> |
24 | #include <linux/regmap.h> |
25 | #include <linux/slab.h> |
26 | |
27 | struct regmap_mmio_context { |
28 | void __iomem *regs; |
29 | unsigned val_bytes; |
30 | struct clk *clk; |
31 | }; |
32 | |
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) |
36 | { |
37 | struct regmap_mmio_context *ctx = context; |
38 | u32 offset; |
39 | int ret; |
40 | |
41 | BUG_ON(reg_size != 4); |
42 | |
43 | if (ctx->clk) { |
44 | ret = clk_enable(ctx->clk); |
45 | if (ret < 0) |
46 | return ret; |
47 | } |
48 | |
49 | offset = *(u32 *)reg; |
50 | |
51 | while (val_size) { |
52 | switch (ctx->val_bytes) { |
53 | case 1: |
54 | writeb(*(u8 *)val, ctx->regs + offset); |
55 | break; |
56 | case 2: |
57 | writew(*(u16 *)val, ctx->regs + offset); |
58 | break; |
59 | case 4: |
60 | writel(*(u32 *)val, ctx->regs + offset); |
61 | break; |
62 | #ifdef CONFIG_64BIT |
63 | case 8: |
64 | writeq(*(u64 *)val, ctx->regs + offset); |
65 | break; |
66 | #endif |
67 | default: |
68 | /* Should be caught by regmap_mmio_check_config */ |
69 | BUG(); |
70 | } |
71 | val_size -= ctx->val_bytes; |
72 | val += ctx->val_bytes; |
73 | offset += ctx->val_bytes; |
74 | } |
75 | |
76 | if (ctx->clk) |
77 | clk_disable(ctx->clk); |
78 | |
79 | return 0; |
80 | } |
81 | |
82 | static int regmap_mmio_write(void *context, const void *data, size_t count) |
83 | { |
84 | BUG_ON(count < 4); |
85 | |
86 | return regmap_mmio_gather_write(context, data, 4, data + 4, count - 4); |
87 | } |
88 | |
89 | static int regmap_mmio_read(void *context, |
90 | const void *reg, size_t reg_size, |
91 | void *val, size_t val_size) |
92 | { |
93 | struct regmap_mmio_context *ctx = context; |
94 | u32 offset; |
95 | int ret; |
96 | |
97 | BUG_ON(reg_size != 4); |
98 | |
99 | if (ctx->clk) { |
100 | ret = clk_enable(ctx->clk); |
101 | if (ret < 0) |
102 | return ret; |
103 | } |
104 | |
105 | offset = *(u32 *)reg; |
106 | |
107 | while (val_size) { |
108 | switch (ctx->val_bytes) { |
109 | case 1: |
110 | *(u8 *)val = readb(ctx->regs + offset); |
111 | break; |
112 | case 2: |
113 | *(u16 *)val = readw(ctx->regs + offset); |
114 | break; |
115 | case 4: |
116 | *(u32 *)val = readl(ctx->regs + offset); |
117 | break; |
118 | #ifdef CONFIG_64BIT |
119 | case 8: |
120 | *(u64 *)val = readq(ctx->regs + offset); |
121 | break; |
122 | #endif |
123 | default: |
124 | /* Should be caught by regmap_mmio_check_config */ |
125 | BUG(); |
126 | } |
127 | val_size -= ctx->val_bytes; |
128 | val += ctx->val_bytes; |
129 | offset += ctx->val_bytes; |
130 | } |
131 | |
132 | if (ctx->clk) |
133 | clk_disable(ctx->clk); |
134 | |
135 | return 0; |
136 | } |
137 | |
138 | static void regmap_mmio_free_context(void *context) |
139 | { |
140 | struct regmap_mmio_context *ctx = context; |
141 | |
142 | if (ctx->clk) { |
143 | clk_unprepare(ctx->clk); |
144 | clk_put(ctx->clk); |
145 | } |
146 | kfree(context); |
147 | } |
148 | |
149 | static struct regmap_bus regmap_mmio = { |
150 | .fast_io = true, |
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, |
157 | }; |
158 | |
159 | static struct regmap_mmio_context *regmap_mmio_gen_context(struct device *dev, |
160 | const char *clk_id, |
161 | void __iomem *regs, |
162 | const struct regmap_config *config) |
163 | { |
164 | struct regmap_mmio_context *ctx; |
165 | int min_stride; |
166 | int ret; |
167 | |
168 | if (config->reg_bits != 32) |
169 | return ERR_PTR(-EINVAL); |
170 | |
171 | if (config->pad_bits) |
172 | return ERR_PTR(-EINVAL); |
173 | |
174 | switch (config->val_bits) { |
175 | case 8: |
176 | /* The core treats 0 as 1 */ |
177 | min_stride = 0; |
178 | break; |
179 | case 16: |
180 | min_stride = 2; |
181 | break; |
182 | case 32: |
183 | min_stride = 4; |
184 | break; |
185 | #ifdef CONFIG_64BIT |
186 | case 64: |
187 | min_stride = 8; |
188 | break; |
189 | #endif |
190 | break; |
191 | default: |
192 | return ERR_PTR(-EINVAL); |
193 | } |
194 | |
195 | if (config->reg_stride < min_stride) |
196 | return ERR_PTR(-EINVAL); |
197 | |
198 | switch (config->reg_format_endian) { |
199 | case REGMAP_ENDIAN_DEFAULT: |
200 | case REGMAP_ENDIAN_NATIVE: |
201 | break; |
202 | default: |
203 | return ERR_PTR(-EINVAL); |
204 | } |
205 | |
206 | ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); |
207 | if (!ctx) |
208 | return ERR_PTR(-ENOMEM); |
209 | |
210 | ctx->regs = regs; |
211 | ctx->val_bytes = config->val_bits / 8; |
212 | |
213 | if (clk_id == NULL) |
214 | return ctx; |
215 | |
216 | ctx->clk = clk_get(dev, clk_id); |
217 | if (IS_ERR(ctx->clk)) { |
218 | ret = PTR_ERR(ctx->clk); |
219 | goto err_free; |
220 | } |
221 | |
222 | ret = clk_prepare(ctx->clk); |
223 | if (ret < 0) { |
224 | clk_put(ctx->clk); |
225 | goto err_free; |
226 | } |
227 | |
228 | return ctx; |
229 | |
230 | err_free: |
231 | kfree(ctx); |
232 | |
233 | return ERR_PTR(ret); |
234 | } |
235 | |
236 | /** |
237 | * regmap_init_mmio_clk(): Initialise register map with register clock |
238 | * |
239 | * @dev: Device that will be interacted with |
240 | * @clk_id: register clock consumer ID |
241 | * @regs: Pointer to memory-mapped IO region |
242 | * @config: Configuration for register map |
243 | * |
244 | * The return value will be an ERR_PTR() on error or a valid pointer to |
245 | * a struct regmap. |
246 | */ |
247 | struct regmap *regmap_init_mmio_clk(struct device *dev, const char *clk_id, |
248 | void __iomem *regs, |
249 | const struct regmap_config *config) |
250 | { |
251 | struct regmap_mmio_context *ctx; |
252 | |
253 | ctx = regmap_mmio_gen_context(dev, clk_id, regs, config); |
254 | if (IS_ERR(ctx)) |
255 | return ERR_CAST(ctx); |
256 | |
257 | return regmap_init(dev, ®map_mmio, ctx, config); |
258 | } |
259 | EXPORT_SYMBOL_GPL(regmap_init_mmio_clk); |
260 | |
261 | /** |
262 | * devm_regmap_init_mmio_clk(): Initialise managed register map with clock |
263 | * |
264 | * @dev: Device that will be interacted with |
265 | * @clk_id: register clock consumer ID |
266 | * @regs: Pointer to memory-mapped IO region |
267 | * @config: Configuration for register map |
268 | * |
269 | * The return value will be an ERR_PTR() on error or a valid pointer |
270 | * to a struct regmap. The regmap will be automatically freed by the |
271 | * device management code. |
272 | */ |
273 | struct regmap *devm_regmap_init_mmio_clk(struct device *dev, const char *clk_id, |
274 | void __iomem *regs, |
275 | const struct regmap_config *config) |
276 | { |
277 | struct regmap_mmio_context *ctx; |
278 | |
279 | ctx = regmap_mmio_gen_context(dev, clk_id, regs, config); |
280 | if (IS_ERR(ctx)) |
281 | return ERR_CAST(ctx); |
282 | |
283 | return devm_regmap_init(dev, ®map_mmio, ctx, config); |
284 | } |
285 | EXPORT_SYMBOL_GPL(devm_regmap_init_mmio_clk); |
286 | |
287 | MODULE_LICENSE("GPL v2"); |
288 |
Branches:
ben-wpan
ben-wpan-stefan
javiroman/ks7010
jz-2.6.34
jz-2.6.34-rc5
jz-2.6.34-rc6
jz-2.6.34-rc7
jz-2.6.35
jz-2.6.36
jz-2.6.37
jz-2.6.38
jz-2.6.39
jz-3.0
jz-3.1
jz-3.11
jz-3.12
jz-3.13
jz-3.15
jz-3.16
jz-3.18-dt
jz-3.2
jz-3.3
jz-3.4
jz-3.5
jz-3.6
jz-3.6-rc2-pwm
jz-3.9
jz-3.9-clk
jz-3.9-rc8
jz47xx
jz47xx-2.6.38
master
Tags:
od-2011-09-04
od-2011-09-18
v2.6.34-rc5
v2.6.34-rc6
v2.6.34-rc7
v3.9