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