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 | |
| parent | 5dea215028686a67e815c32a54dc89fb3467ab05 (diff) | |
| parent | 878ec67b3ac528a2b6d44055f049cdbb9cfda30c (diff) | |
Merge remote-tracking branch 'regmap/topic/mmio' into regmap-next
| -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, |
