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