diff options
-rw-r--r-- | drivers/base/regmap/regmap-mmio.c | 79 | ||||
-rw-r--r-- | include/linux/regmap.h | 47 |
2 files changed, 107 insertions, 19 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"); |
diff --git a/include/linux/regmap.h b/include/linux/regmap.h index 9e790f956025..017b3bd085a2 100644 --- a/include/linux/regmap.h +++ b/include/linux/regmap.h | |||
@@ -299,9 +299,9 @@ struct regmap *regmap_init_i2c(struct i2c_client *i2c, | |||
299 | const struct regmap_config *config); | 299 | const struct regmap_config *config); |
300 | struct regmap *regmap_init_spi(struct spi_device *dev, | 300 | struct regmap *regmap_init_spi(struct spi_device *dev, |
301 | const struct regmap_config *config); | 301 | const struct regmap_config *config); |
302 | struct regmap *regmap_init_mmio(struct device *dev, | 302 | struct regmap *regmap_init_mmio_clk(struct device *dev, const char *clk_id, |
303 | void __iomem *regs, | 303 | void __iomem *regs, |
304 | const struct regmap_config *config); | 304 | const struct regmap_config *config); |
305 | 305 | ||
306 | struct regmap *devm_regmap_init(struct device *dev, | 306 | struct regmap *devm_regmap_init(struct device *dev, |
307 | const struct regmap_bus *bus, | 307 | const struct regmap_bus *bus, |
@@ -311,9 +311,44 @@ struct regmap *devm_regmap_init_i2c(struct i2c_client *i2c, | |||
311 | const struct regmap_config *config); | 311 | const struct regmap_config *config); |
312 | struct regmap *devm_regmap_init_spi(struct spi_device *dev, | 312 | struct regmap *devm_regmap_init_spi(struct spi_device *dev, |
313 | const struct regmap_config *config); | 313 | const struct regmap_config *config); |
314 | struct regmap *devm_regmap_init_mmio(struct device *dev, | 314 | struct regmap *devm_regmap_init_mmio_clk(struct device *dev, const char *clk_id, |
315 | void __iomem *regs, | 315 | void __iomem *regs, |
316 | const struct regmap_config *config); | 316 | const struct regmap_config *config); |
317 | |||
318 | /** | ||
319 | * regmap_init_mmio(): Initialise register map | ||
320 | * | ||
321 | * @dev: Device that will be interacted with | ||
322 | * @regs: Pointer to memory-mapped IO region | ||
323 | * @config: Configuration for register map | ||
324 | * | ||
325 | * The return value will be an ERR_PTR() on error or a valid pointer to | ||
326 | * a struct regmap. | ||
327 | */ | ||
328 | static inline struct regmap *regmap_init_mmio(struct device *dev, | ||
329 | void __iomem *regs, | ||
330 | const struct regmap_config *config) | ||
331 | { | ||
332 | return regmap_init_mmio_clk(dev, NULL, regs, config); | ||
333 | } | ||
334 | |||
335 | /** | ||
336 | * devm_regmap_init_mmio(): Initialise managed register map | ||
337 | * | ||
338 | * @dev: Device that will be interacted with | ||
339 | * @regs: Pointer to memory-mapped IO region | ||
340 | * @config: Configuration for register map | ||
341 | * | ||
342 | * The return value will be an ERR_PTR() on error or a valid pointer | ||
343 | * to a struct regmap. The regmap will be automatically freed by the | ||
344 | * device management code. | ||
345 | */ | ||
346 | static inline struct regmap *devm_regmap_init_mmio(struct device *dev, | ||
347 | void __iomem *regs, | ||
348 | const struct regmap_config *config) | ||
349 | { | ||
350 | return devm_regmap_init_mmio_clk(dev, NULL, regs, config); | ||
351 | } | ||
317 | 352 | ||
318 | void regmap_exit(struct regmap *map); | 353 | void regmap_exit(struct regmap *map); |
319 | int regmap_reinit_cache(struct regmap *map, | 354 | int regmap_reinit_cache(struct regmap *map, |