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 clk_put(ctx->clk); 210 } 211 kfree(context); 212 } 213 214 static const struct regmap_bus regmap_mmio = { 215 .fast_io = true, 216 .reg_write = regmap_mmio_write, 217 .reg_read = regmap_mmio_read, 218 .free_context = regmap_mmio_free_context, 219 .val_format_endian_default = REGMAP_ENDIAN_LITTLE, 220 }; 221 222 static struct regmap_mmio_context *regmap_mmio_gen_context(struct device *dev, 223 const char *clk_id, 224 void __iomem *regs, 225 const struct regmap_config *config) 226 { 227 struct regmap_mmio_context *ctx; 228 int min_stride; 229 int ret; 230 231 ret = regmap_mmio_regbits_check(config->reg_bits); 232 if (ret) 233 return ERR_PTR(ret); 234 235 if (config->pad_bits) 236 return ERR_PTR(-EINVAL); 237 238 min_stride = regmap_mmio_get_min_stride(config->val_bits); 239 if (min_stride < 0) 240 return ERR_PTR(min_stride); 241 242 if (config->reg_stride < min_stride) 243 return ERR_PTR(-EINVAL); 244 245 ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); 246 if (!ctx) 247 return ERR_PTR(-ENOMEM); 248 249 ctx->regs = regs; 250 ctx->val_bytes = config->val_bits / 8; 251 ctx->clk = ERR_PTR(-ENODEV); 252 253 switch (regmap_get_val_endian(dev, ®map_mmio, config)) { 254 case REGMAP_ENDIAN_DEFAULT: 255 case REGMAP_ENDIAN_LITTLE: 256 #ifdef __LITTLE_ENDIAN 257 case REGMAP_ENDIAN_NATIVE: 258 #endif 259 switch (config->val_bits) { 260 case 8: 261 ctx->reg_read = regmap_mmio_read8; 262 ctx->reg_write = regmap_mmio_write8; 263 break; 264 case 16: 265 ctx->reg_read = regmap_mmio_read16le; 266 ctx->reg_write = regmap_mmio_write16le; 267 break; 268 case 32: 269 ctx->reg_read = regmap_mmio_read32le; 270 ctx->reg_write = regmap_mmio_write32le; 271 break; 272 #ifdef CONFIG_64BIT 273 case 64: 274 ctx->reg_read = regmap_mmio_read64le; 275 ctx->reg_write = regmap_mmio_write64le; 276 break; 277 #endif 278 default: 279 ret = -EINVAL; 280 goto err_free; 281 } 282 break; 283 case REGMAP_ENDIAN_BIG: 284 #ifdef __BIG_ENDIAN 285 case REGMAP_ENDIAN_NATIVE: 286 #endif 287 switch (config->val_bits) { 288 case 8: 289 ctx->reg_read = regmap_mmio_read8; 290 ctx->reg_write = regmap_mmio_write8; 291 break; 292 case 16: 293 ctx->reg_read = regmap_mmio_read16be; 294 ctx->reg_write = regmap_mmio_write16be; 295 break; 296 case 32: 297 ctx->reg_read = regmap_mmio_read32be; 298 ctx->reg_write = regmap_mmio_write32be; 299 break; 300 default: 301 ret = -EINVAL; 302 goto err_free; 303 } 304 break; 305 default: 306 ret = -EINVAL; 307 goto err_free; 308 } 309 310 if (clk_id == NULL) 311 return ctx; 312 313 ctx->clk = clk_get(dev, clk_id); 314 if (IS_ERR(ctx->clk)) { 315 ret = PTR_ERR(ctx->clk); 316 goto err_free; 317 } 318 319 ret = clk_prepare(ctx->clk); 320 if (ret < 0) { 321 clk_put(ctx->clk); 322 goto err_free; 323 } 324 325 return ctx; 326 327 err_free: 328 kfree(ctx); 329 330 return ERR_PTR(ret); 331 } 332 333 struct regmap *__regmap_init_mmio_clk(struct device *dev, const char *clk_id, 334 void __iomem *regs, 335 const struct regmap_config *config, 336 struct lock_class_key *lock_key, 337 const char *lock_name) 338 { 339 struct regmap_mmio_context *ctx; 340 341 ctx = regmap_mmio_gen_context(dev, clk_id, regs, config); 342 if (IS_ERR(ctx)) 343 return ERR_CAST(ctx); 344 345 return __regmap_init(dev, ®map_mmio, ctx, config, 346 lock_key, lock_name); 347 } 348 EXPORT_SYMBOL_GPL(__regmap_init_mmio_clk); 349 350 struct regmap *__devm_regmap_init_mmio_clk(struct device *dev, 351 const char *clk_id, 352 void __iomem *regs, 353 const struct regmap_config *config, 354 struct lock_class_key *lock_key, 355 const char *lock_name) 356 { 357 struct regmap_mmio_context *ctx; 358 359 ctx = regmap_mmio_gen_context(dev, clk_id, regs, config); 360 if (IS_ERR(ctx)) 361 return ERR_CAST(ctx); 362 363 return __devm_regmap_init(dev, ®map_mmio, ctx, config, 364 lock_key, lock_name); 365 } 366 EXPORT_SYMBOL_GPL(__devm_regmap_init_mmio_clk); 367 368 int regmap_mmio_attach_clk(struct regmap *map, struct clk *clk) 369 { 370 struct regmap_mmio_context *ctx = map->bus_context; 371 372 ctx->clk = clk; 373 ctx->attached_clk = true; 374 375 return clk_prepare(ctx->clk); 376 } 377 EXPORT_SYMBOL_GPL(regmap_mmio_attach_clk); 378 379 void regmap_mmio_detach_clk(struct regmap *map) 380 { 381 struct regmap_mmio_context *ctx = map->bus_context; 382 383 clk_unprepare(ctx->clk); 384 385 ctx->attached_clk = false; 386 ctx->clk = NULL; 387 } 388 EXPORT_SYMBOL_GPL(regmap_mmio_detach_clk); 389 390 MODULE_LICENSE("GPL v2"); 391