diff options
author | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2013-02-14 12:11:08 -0500 |
---|---|---|
committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2013-02-14 12:11:08 -0500 |
commit | a31f68497e07f5fec7155bc07dc633fc6eaa0adb (patch) | |
tree | 9324a5f1327a5a9dc0548dd21d5dcb569149a834 /drivers/base | |
parent | 5dea215028686a67e815c32a54dc89fb3467ab05 (diff) | |
parent | 878ec67b3ac528a2b6d44055f049cdbb9cfda30c (diff) |
Merge remote-tracking branch 'regmap/topic/mmio' into regmap-next
Diffstat (limited to 'drivers/base')
-rw-r--r-- | drivers/base/regmap/regmap-mmio.c | 79 |
1 files changed, 66 insertions, 13 deletions
diff --git a/drivers/base/regmap/regmap-mmio.c b/drivers/base/regmap/regmap-mmio.c index f05fc74dd84a..98745dd77e8c 100644 --- a/drivers/base/regmap/regmap-mmio.c +++ b/drivers/base/regmap/regmap-mmio.c | |||
@@ -16,6 +16,7 @@ | |||
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | 16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
17 | */ | 17 | */ |
18 | 18 | ||
19 | #include <linux/clk.h> | ||
19 | #include <linux/err.h> | 20 | #include <linux/err.h> |
20 | #include <linux/init.h> | 21 | #include <linux/init.h> |
21 | #include <linux/io.h> | 22 | #include <linux/io.h> |
@@ -26,6 +27,7 @@ | |||
26 | struct regmap_mmio_context { | 27 | struct regmap_mmio_context { |
27 | void __iomem *regs; | 28 | void __iomem *regs; |
28 | unsigned val_bytes; | 29 | unsigned val_bytes; |
30 | struct clk *clk; | ||
29 | }; | 31 | }; |
30 | 32 | ||
31 | static int regmap_mmio_gather_write(void *context, | 33 | static int regmap_mmio_gather_write(void *context, |
@@ -34,9 +36,16 @@ static int regmap_mmio_gather_write(void *context, | |||
34 | { | 36 | { |
35 | struct regmap_mmio_context *ctx = context; | 37 | struct regmap_mmio_context *ctx = context; |
36 | u32 offset; | 38 | u32 offset; |
39 | int ret; | ||
37 | 40 | ||
38 | BUG_ON(reg_size != 4); | 41 | BUG_ON(reg_size != 4); |
39 | 42 | ||
43 | if (ctx->clk) { | ||
44 | ret = clk_enable(ctx->clk); | ||
45 | if (ret < 0) | ||
46 | return ret; | ||
47 | } | ||
48 | |||
40 | offset = *(u32 *)reg; | 49 | offset = *(u32 *)reg; |
41 | 50 | ||
42 | while (val_size) { | 51 | while (val_size) { |
@@ -64,6 +73,9 @@ static int regmap_mmio_gather_write(void *context, | |||
64 | offset += ctx->val_bytes; | 73 | offset += ctx->val_bytes; |
65 | } | 74 | } |
66 | 75 | ||
76 | if (ctx->clk) | ||
77 | clk_disable(ctx->clk); | ||
78 | |||
67 | return 0; | 79 | return 0; |
68 | } | 80 | } |
69 | 81 | ||
@@ -80,9 +92,16 @@ static int regmap_mmio_read(void *context, | |||
80 | { | 92 | { |
81 | struct regmap_mmio_context *ctx = context; | 93 | struct regmap_mmio_context *ctx = context; |
82 | u32 offset; | 94 | u32 offset; |
95 | int ret; | ||
83 | 96 | ||
84 | BUG_ON(reg_size != 4); | 97 | BUG_ON(reg_size != 4); |
85 | 98 | ||
99 | if (ctx->clk) { | ||
100 | ret = clk_enable(ctx->clk); | ||
101 | if (ret < 0) | ||
102 | return ret; | ||
103 | } | ||
104 | |||
86 | offset = *(u32 *)reg; | 105 | offset = *(u32 *)reg; |
87 | 106 | ||
88 | while (val_size) { | 107 | while (val_size) { |
@@ -110,11 +129,20 @@ static int regmap_mmio_read(void *context, | |||
110 | offset += ctx->val_bytes; | 129 | offset += ctx->val_bytes; |
111 | } | 130 | } |
112 | 131 | ||
132 | if (ctx->clk) | ||
133 | clk_disable(ctx->clk); | ||
134 | |||
113 | return 0; | 135 | return 0; |
114 | } | 136 | } |
115 | 137 | ||
116 | static void regmap_mmio_free_context(void *context) | 138 | static void regmap_mmio_free_context(void *context) |
117 | { | 139 | { |
140 | struct regmap_mmio_context *ctx = context; | ||
141 | |||
142 | if (ctx->clk) { | ||
143 | clk_unprepare(ctx->clk); | ||
144 | clk_put(ctx->clk); | ||
145 | } | ||
118 | kfree(context); | 146 | kfree(context); |
119 | } | 147 | } |
120 | 148 | ||
@@ -128,11 +156,14 @@ static struct regmap_bus regmap_mmio = { | |||
128 | .val_format_endian_default = REGMAP_ENDIAN_NATIVE, | 156 | .val_format_endian_default = REGMAP_ENDIAN_NATIVE, |
129 | }; | 157 | }; |
130 | 158 | ||
131 | static struct regmap_mmio_context *regmap_mmio_gen_context(void __iomem *regs, | 159 | static struct regmap_mmio_context *regmap_mmio_gen_context(struct device *dev, |
160 | const char *clk_id, | ||
161 | void __iomem *regs, | ||
132 | const struct regmap_config *config) | 162 | const struct regmap_config *config) |
133 | { | 163 | { |
134 | struct regmap_mmio_context *ctx; | 164 | struct regmap_mmio_context *ctx; |
135 | int min_stride; | 165 | int min_stride; |
166 | int ret; | ||
136 | 167 | ||
137 | if (config->reg_bits != 32) | 168 | if (config->reg_bits != 32) |
138 | return ERR_PTR(-EINVAL); | 169 | return ERR_PTR(-EINVAL); |
@@ -179,37 +210,59 @@ static struct regmap_mmio_context *regmap_mmio_gen_context(void __iomem *regs, | |||
179 | ctx->regs = regs; | 210 | ctx->regs = regs; |
180 | ctx->val_bytes = config->val_bits / 8; | 211 | ctx->val_bytes = config->val_bits / 8; |
181 | 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 | |||
182 | return ctx; | 228 | return ctx; |
229 | |||
230 | err_free: | ||
231 | kfree(ctx); | ||
232 | |||
233 | return ERR_PTR(ret); | ||
183 | } | 234 | } |
184 | 235 | ||
185 | /** | 236 | /** |
186 | * regmap_init_mmio(): Initialise register map | 237 | * regmap_init_mmio_clk(): Initialise register map with register clock |
187 | * | 238 | * |
188 | * @dev: Device that will be interacted with | 239 | * @dev: Device that will be interacted with |
240 | * @clk_id: register clock consumer ID | ||
189 | * @regs: Pointer to memory-mapped IO region | 241 | * @regs: Pointer to memory-mapped IO region |
190 | * @config: Configuration for register map | 242 | * @config: Configuration for register map |
191 | * | 243 | * |
192 | * The return value will be an ERR_PTR() on error or a valid pointer to | 244 | * The return value will be an ERR_PTR() on error or a valid pointer to |
193 | * a struct regmap. | 245 | * a struct regmap. |
194 | */ | 246 | */ |
195 | struct regmap *regmap_init_mmio(struct device *dev, | 247 | struct regmap *regmap_init_mmio_clk(struct device *dev, const char *clk_id, |
196 | void __iomem *regs, | 248 | void __iomem *regs, |
197 | const struct regmap_config *config) | 249 | const struct regmap_config *config) |
198 | { | 250 | { |
199 | struct regmap_mmio_context *ctx; | 251 | struct regmap_mmio_context *ctx; |
200 | 252 | ||
201 | ctx = regmap_mmio_gen_context(regs, config); | 253 | ctx = regmap_mmio_gen_context(dev, clk_id, regs, config); |
202 | if (IS_ERR(ctx)) | 254 | if (IS_ERR(ctx)) |
203 | return ERR_CAST(ctx); | 255 | return ERR_CAST(ctx); |
204 | 256 | ||
205 | return regmap_init(dev, ®map_mmio, ctx, config); | 257 | return regmap_init(dev, ®map_mmio, ctx, config); |
206 | } | 258 | } |
207 | EXPORT_SYMBOL_GPL(regmap_init_mmio); | 259 | EXPORT_SYMBOL_GPL(regmap_init_mmio_clk); |
208 | 260 | ||
209 | /** | 261 | /** |
210 | * devm_regmap_init_mmio(): Initialise managed register map | 262 | * devm_regmap_init_mmio_clk(): Initialise managed register map with clock |
211 | * | 263 | * |
212 | * @dev: Device that will be interacted with | 264 | * @dev: Device that will be interacted with |
265 | * @clk_id: register clock consumer ID | ||
213 | * @regs: Pointer to memory-mapped IO region | 266 | * @regs: Pointer to memory-mapped IO region |
214 | * @config: Configuration for register map | 267 | * @config: Configuration for register map |
215 | * | 268 | * |
@@ -217,18 +270,18 @@ EXPORT_SYMBOL_GPL(regmap_init_mmio); | |||
217 | * to a struct regmap. The regmap will be automatically freed by the | 270 | * to a struct regmap. The regmap will be automatically freed by the |
218 | * device management code. | 271 | * device management code. |
219 | */ | 272 | */ |
220 | struct regmap *devm_regmap_init_mmio(struct device *dev, | 273 | struct regmap *devm_regmap_init_mmio_clk(struct device *dev, const char *clk_id, |
221 | void __iomem *regs, | 274 | void __iomem *regs, |
222 | const struct regmap_config *config) | 275 | const struct regmap_config *config) |
223 | { | 276 | { |
224 | struct regmap_mmio_context *ctx; | 277 | struct regmap_mmio_context *ctx; |
225 | 278 | ||
226 | ctx = regmap_mmio_gen_context(regs, config); | 279 | ctx = regmap_mmio_gen_context(dev, clk_id, regs, config); |
227 | if (IS_ERR(ctx)) | 280 | if (IS_ERR(ctx)) |
228 | return ERR_CAST(ctx); | 281 | return ERR_CAST(ctx); |
229 | 282 | ||
230 | return devm_regmap_init(dev, ®map_mmio, ctx, config); | 283 | return devm_regmap_init(dev, ®map_mmio, ctx, config); |
231 | } | 284 | } |
232 | EXPORT_SYMBOL_GPL(devm_regmap_init_mmio); | 285 | EXPORT_SYMBOL_GPL(devm_regmap_init_mmio_clk); |
233 | 286 | ||
234 | MODULE_LICENSE("GPL v2"); | 287 | MODULE_LICENSE("GPL v2"); |