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/io.h> 22 #include <linux/module.h> 23 #include <linux/regmap.h> 24 #include <linux/slab.h> 25 26 #include "internal.h" 27 28 struct regmap_mmio_context { 29 void __iomem *regs; 30 unsigned val_bytes; 31 32 bool attached_clk; 33 struct clk *clk; 34 35 void (*reg_write)(struct regmap_mmio_context *ctx, 36 unsigned int reg, unsigned int val); 37 unsigned int (*reg_read)(struct regmap_mmio_context *ctx, 38 unsigned int reg); 39 }; 40 41 static int regmap_mmio_regbits_check(size_t reg_bits) 42 { 43 switch (reg_bits) { 44 case 8: 45 case 16: 46 case 32: 47 #ifdef CONFIG_64BIT 48 case 64: 49 #endif 50 return 0; 51 default: 52 return -EINVAL; 53 } 54 } 55 56 static int regmap_mmio_get_min_stride(size_t val_bits) 57 { 58 int min_stride; 59 60 switch (val_bits) { 61 case 8: 62 /* The core treats 0 as 1 */ 63 min_stride = 0; 64 return 0; 65 case 16: 66 min_stride = 2; 67 break; 68 case 32: 69 min_stride = 4; 70 break; 71 #ifdef CONFIG_64BIT 72 case 64: 73 min_stride = 8; 74 break; 75 #endif 76 default: 77 return -EINVAL; 78 } 79 80 return min_stride; 81 } 82 83 static void regmap_mmio_write8(struct regmap_mmio_context *ctx, 84 unsigned int reg, 85 unsigned int val) 86 { 87 writeb(val, ctx->regs + reg); 88 } 89 90 static void regmap_mmio_write16le(struct regmap_mmio_context *ctx, 91 unsigned int reg, 92 unsigned int val) 93 { 94 writew(val, ctx->regs + reg); 95 } 96 97 static void regmap_mmio_write16be(struct regmap_mmio_context *ctx, 98 unsigned int reg, 99 unsigned int val) 100 { 101 iowrite16be(val, ctx->regs + reg); 102 } 103 104 static void regmap_mmio_write32le(struct regmap_mmio_context *ctx, 105 unsigned int reg, 106 unsigned int val) 107 { 108 writel(val, ctx->regs + reg); 109 } 110 111 static void regmap_mmio_write32be(struct regmap_mmio_context *ctx, 112 unsigned int reg, 113 unsigned int val) 114 { 115 iowrite32be(val, ctx->regs + reg); 116 } 117 118 #ifdef CONFIG_64BIT 119 static void regmap_mmio_write64le(struct regmap_mmio_context *ctx, 120 unsigned int reg, 121 unsigned int val) 122 { 123 writeq(val, ctx->regs + reg); 124 } 125 #endif 126 127 static int regmap_mmio_write(void *context, unsigned int reg, unsigned int val) 128 { 129 struct regmap_mmio_context *ctx = context; 130 int ret; 131 132 if (!IS_ERR(ctx->clk)) { 133 ret = clk_enable(ctx->clk); 134 if (ret < 0) 135 return ret; 136 } 137 138 ctx->reg_write(ctx, reg, val); 139 140 if (!IS_ERR(ctx->clk)) 141 clk_disable(ctx->clk); 142 143 return 0; 144 } 145 146 static unsigned int regmap_mmio_read8(struct regmap_mmio_context *ctx, 147 unsigned int reg) 148 { 149 return readb(ctx->regs + reg); 150 } 151 152 static unsigned int regmap_mmio_read16le(struct regmap_mmio_context *ctx, 153 unsigned int reg) 154 { 155 return readw(ctx->regs + reg); 156 } 157 158 static unsigned int regmap_mmio_read16be(struct regmap_mmio_context *ctx, 159 unsigned int reg) 160 { 161 return ioread16be(ctx->regs + reg); 162 } 163 164 static unsigned int regmap_mmio_read32le(struct regmap_mmio_context *ctx, 165 unsigned int reg) 166 { 167 return readl(ctx->regs + reg); 168 } 169 170 static unsigned int regmap_mmio_read32be(struct regmap_mmio_context *ctx, 171 unsigned int reg) 172 { 173 return ioread32be(ctx->regs + reg); 174 } 175 176 #ifdef CONFIG_64BIT 177 static unsigned int regmap_mmio_read64le(struct regmap_mmio_context *ctx, 178 unsigned int reg) 179 { 180 return readq(ctx->regs + reg); 181 } 182 #endif 183 184 static int regmap_mmio_read(void *context, unsigned int reg, unsigned int *val) 185 { 186 struct regmap_mmio_context *ctx = context; 187 int ret; 188 189 if (!IS_ERR(ctx->clk)) { 190 ret = clk_enable(ctx->clk); 191 if (ret < 0) 192 return ret; 193 } 194 195 *val = ctx->reg_read(ctx, reg); 196 197 if (!IS_ERR(ctx->clk)) 198 clk_disable(ctx->clk); 199 200 return 0; 201 } 202 203 static void regmap_mmio_free_context(void *context) 204 { 205 struct regmap_mmio_context *ctx = context; 206 207 if (!IS_ERR(ctx->clk)) { 208 clk_unprepare(ctx->clk); 209 if (!ctx->attached_clk) 210 clk_put(ctx->clk); 211 } 212 kfree(context); 213 } 214 215 static const struct regmap_bus regmap_mmio = { 216 .fast_io = true, 217 .reg_write = regmap_mmio_write, 218 .reg_read = regmap_mmio_read, 219 .free_context = regmap_mmio_free_context, 220 .val_format_endian_default = REGMAP_ENDIAN_LITTLE, 221 }; 222 223 static struct regmap_mmio_context *regmap_mmio_gen_context(struct device *dev, 224 const char *clk_id, 225 void __iomem *regs, 226 const struct regmap_config *config) 227 { 228 struct regmap_mmio_context *ctx; 229 int min_stride; 230 int ret; 231 232 ret = regmap_mmio_regbits_check(config->reg_bits); 233 if (ret) 234 return ERR_PTR(ret); 235 236 if (config->pad_bits) 237 return ERR_PTR(-EINVAL); 238 239 min_stride = regmap_mmio_get_min_stride(config->val_bits); 240 if (min_stride < 0) 241 return ERR_PTR(min_stride); 242 243 if (config->reg_stride < min_stride) 244 return ERR_PTR(-EINVAL); 245 246 ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); 247 if (!ctx) 248 return ERR_PTR(-ENOMEM); 249 250 ctx->regs = regs; 251 ctx->val_bytes = config->val_bits / 8; 252 ctx->clk = ERR_PTR(-ENODEV); 253 254 switch (regmap_get_val_endian(dev, ®map_mmio, config)) { 255 case REGMAP_ENDIAN_DEFAULT: 256 case REGMAP_ENDIAN_LITTLE: 257 #ifdef __LITTLE_ENDIAN 258 case REGMAP_ENDIAN_NATIVE: 259 #endif 260 switch (config->val_bits) { 261 case 8: 262 ctx->reg_read = regmap_mmio_read8; 263 ctx->reg_write = regmap_mmio_write8; 264 break; 265 case 16: 266 ctx->reg_read = regmap_mmio_read16le; 267 ctx->reg_write = regmap_mmio_write16le; 268 break; 269 case 32: 270 ctx->reg_read = regmap_mmio_read32le; 271 ctx->reg_write = regmap_mmio_write32le; 272 break; 273 #ifdef CONFIG_64BIT 274 case 64: 275 ctx->reg_read = regmap_mmio_read64le; 276 ctx->reg_write = regmap_mmio_write64le; 277 break; 278 #endif 279 default: 280 ret = -EINVAL; 281 goto err_free; 282 } 283 break; 284 case REGMAP_ENDIAN_BIG: 285 #ifdef __BIG_ENDIAN 286 case REGMAP_ENDIAN_NATIVE: 287 #endif 288 switch (config->val_bits) { 289 case 8: 290 ctx->reg_read = regmap_mmio_read8; 291 ctx->reg_write = regmap_mmio_write8; 292 break; 293 case 16: 294 ctx->reg_read = regmap_mmio_read16be; 295 ctx->reg_write = regmap_mmio_write16be; 296 break; 297 case 32: 298 ctx->reg_read = regmap_mmio_read32be; 299 ctx->reg_write = regmap_mmio_write32be; 300 break; 301 default: 302 ret = -EINVAL; 303 goto err_free; 304 } 305 break; 306 default: 307 ret = -EINVAL; 308 goto err_free; 309 } 310 311 if (clk_id == NULL) 312 return ctx; 313 314 ctx->clk = clk_get(dev, clk_id); 315 if (IS_ERR(ctx->clk)) { 316 ret = PTR_ERR(ctx->clk); 317 goto err_free; 318 } 319 320 ret = clk_prepare(ctx->clk); 321 if (ret < 0) { 322 clk_put(ctx->clk); 323 goto err_free; 324 } 325 326 return ctx; 327 328 err_free: 329 kfree(ctx); 330 331 return ERR_PTR(ret); 332 } 333 334 struct regmap *__regmap_init_mmio_clk(struct device *dev, const char *clk_id, 335 void __iomem *regs, 336 const struct regmap_config *config, 337 struct lock_class_key *lock_key, 338 const char *lock_name) 339 { 340 struct regmap_mmio_context *ctx; 341 342 ctx = regmap_mmio_gen_context(dev, clk_id, regs, config); 343 if (IS_ERR(ctx)) 344 return ERR_CAST(ctx); 345 346 return __regmap_init(dev, ®map_mmio, ctx, config, 347 lock_key, lock_name); 348 } 349 EXPORT_SYMBOL_GPL(__regmap_init_mmio_clk); 350 351 struct regmap *__devm_regmap_init_mmio_clk(struct device *dev, 352 const char *clk_id, 353 void __iomem *regs, 354 const struct regmap_config *config, 355 struct lock_class_key *lock_key, 356 const char *lock_name) 357 { 358 struct regmap_mmio_context *ctx; 359 360 ctx = regmap_mmio_gen_context(dev, clk_id, regs, config); 361 if (IS_ERR(ctx)) 362 return ERR_CAST(ctx); 363 364 return __devm_regmap_init(dev, ®map_mmio, ctx, config, 365 lock_key, lock_name); 366 } 367 EXPORT_SYMBOL_GPL(__devm_regmap_init_mmio_clk); 368 369 int regmap_mmio_attach_clk(struct regmap *map, struct clk *clk) 370 { 371 struct regmap_mmio_context *ctx = map->bus_context; 372 373 ctx->clk = clk; 374 ctx->attached_clk = true; 375 376 return clk_prepare(ctx->clk); 377 } 378 EXPORT_SYMBOL_GPL(regmap_mmio_attach_clk); 379 380 void regmap_mmio_detach_clk(struct regmap *map) 381 { 382 struct regmap_mmio_context *ctx = map->bus_context; 383 384 clk_unprepare(ctx->clk); 385 386 ctx->attached_clk = false; 387 ctx->clk = NULL; 388 } 389 EXPORT_SYMBOL_GPL(regmap_mmio_detach_clk); 390 391 MODULE_LICENSE("GPL v2"); 392