0001
0002
0003
0004
0005
0006
0007 #include <linux/clk.h>
0008 #include <linux/err.h>
0009 #include <linux/io.h>
0010 #include <linux/module.h>
0011 #include <linux/regmap.h>
0012 #include <linux/slab.h>
0013
0014 #include "internal.h"
0015
0016 struct regmap_mmio_context {
0017 void __iomem *regs;
0018 unsigned int val_bytes;
0019 bool relaxed_mmio;
0020
0021 bool attached_clk;
0022 struct clk *clk;
0023
0024 void (*reg_write)(struct regmap_mmio_context *ctx,
0025 unsigned int reg, unsigned int val);
0026 unsigned int (*reg_read)(struct regmap_mmio_context *ctx,
0027 unsigned int reg);
0028 };
0029
0030 static int regmap_mmio_regbits_check(size_t reg_bits)
0031 {
0032 switch (reg_bits) {
0033 case 8:
0034 case 16:
0035 case 32:
0036 #ifdef CONFIG_64BIT
0037 case 64:
0038 #endif
0039 return 0;
0040 default:
0041 return -EINVAL;
0042 }
0043 }
0044
0045 static int regmap_mmio_get_min_stride(size_t val_bits)
0046 {
0047 int min_stride;
0048
0049 switch (val_bits) {
0050 case 8:
0051
0052 min_stride = 0;
0053 return 0;
0054 case 16:
0055 min_stride = 2;
0056 break;
0057 case 32:
0058 min_stride = 4;
0059 break;
0060 #ifdef CONFIG_64BIT
0061 case 64:
0062 min_stride = 8;
0063 break;
0064 #endif
0065 default:
0066 return -EINVAL;
0067 }
0068
0069 return min_stride;
0070 }
0071
0072 static void regmap_mmio_write8(struct regmap_mmio_context *ctx,
0073 unsigned int reg,
0074 unsigned int val)
0075 {
0076 writeb(val, ctx->regs + reg);
0077 }
0078
0079 static void regmap_mmio_write8_relaxed(struct regmap_mmio_context *ctx,
0080 unsigned int reg,
0081 unsigned int val)
0082 {
0083 writeb_relaxed(val, ctx->regs + reg);
0084 }
0085
0086 static void regmap_mmio_write16le(struct regmap_mmio_context *ctx,
0087 unsigned int reg,
0088 unsigned int val)
0089 {
0090 writew(val, ctx->regs + reg);
0091 }
0092
0093 static void regmap_mmio_write16le_relaxed(struct regmap_mmio_context *ctx,
0094 unsigned int reg,
0095 unsigned int val)
0096 {
0097 writew_relaxed(val, ctx->regs + reg);
0098 }
0099
0100 static void regmap_mmio_write16be(struct regmap_mmio_context *ctx,
0101 unsigned int reg,
0102 unsigned int val)
0103 {
0104 iowrite16be(val, ctx->regs + reg);
0105 }
0106
0107 static void regmap_mmio_write32le(struct regmap_mmio_context *ctx,
0108 unsigned int reg,
0109 unsigned int val)
0110 {
0111 writel(val, ctx->regs + reg);
0112 }
0113
0114 static void regmap_mmio_write32le_relaxed(struct regmap_mmio_context *ctx,
0115 unsigned int reg,
0116 unsigned int val)
0117 {
0118 writel_relaxed(val, ctx->regs + reg);
0119 }
0120
0121 static void regmap_mmio_write32be(struct regmap_mmio_context *ctx,
0122 unsigned int reg,
0123 unsigned int val)
0124 {
0125 iowrite32be(val, ctx->regs + reg);
0126 }
0127
0128 #ifdef CONFIG_64BIT
0129 static void regmap_mmio_write64le(struct regmap_mmio_context *ctx,
0130 unsigned int reg,
0131 unsigned int val)
0132 {
0133 writeq(val, ctx->regs + reg);
0134 }
0135
0136 static void regmap_mmio_write64le_relaxed(struct regmap_mmio_context *ctx,
0137 unsigned int reg,
0138 unsigned int val)
0139 {
0140 writeq_relaxed(val, ctx->regs + reg);
0141 }
0142 #endif
0143
0144 static int regmap_mmio_write(void *context, unsigned int reg, unsigned int val)
0145 {
0146 struct regmap_mmio_context *ctx = context;
0147 int ret;
0148
0149 if (!IS_ERR(ctx->clk)) {
0150 ret = clk_enable(ctx->clk);
0151 if (ret < 0)
0152 return ret;
0153 }
0154
0155 ctx->reg_write(ctx, reg, val);
0156
0157 if (!IS_ERR(ctx->clk))
0158 clk_disable(ctx->clk);
0159
0160 return 0;
0161 }
0162
0163 static unsigned int regmap_mmio_read8(struct regmap_mmio_context *ctx,
0164 unsigned int reg)
0165 {
0166 return readb(ctx->regs + reg);
0167 }
0168
0169 static unsigned int regmap_mmio_read8_relaxed(struct regmap_mmio_context *ctx,
0170 unsigned int reg)
0171 {
0172 return readb_relaxed(ctx->regs + reg);
0173 }
0174
0175 static unsigned int regmap_mmio_read16le(struct regmap_mmio_context *ctx,
0176 unsigned int reg)
0177 {
0178 return readw(ctx->regs + reg);
0179 }
0180
0181 static unsigned int regmap_mmio_read16le_relaxed(struct regmap_mmio_context *ctx,
0182 unsigned int reg)
0183 {
0184 return readw_relaxed(ctx->regs + reg);
0185 }
0186
0187 static unsigned int regmap_mmio_read16be(struct regmap_mmio_context *ctx,
0188 unsigned int reg)
0189 {
0190 return ioread16be(ctx->regs + reg);
0191 }
0192
0193 static unsigned int regmap_mmio_read32le(struct regmap_mmio_context *ctx,
0194 unsigned int reg)
0195 {
0196 return readl(ctx->regs + reg);
0197 }
0198
0199 static unsigned int regmap_mmio_read32le_relaxed(struct regmap_mmio_context *ctx,
0200 unsigned int reg)
0201 {
0202 return readl_relaxed(ctx->regs + reg);
0203 }
0204
0205 static unsigned int regmap_mmio_read32be(struct regmap_mmio_context *ctx,
0206 unsigned int reg)
0207 {
0208 return ioread32be(ctx->regs + reg);
0209 }
0210
0211 #ifdef CONFIG_64BIT
0212 static unsigned int regmap_mmio_read64le(struct regmap_mmio_context *ctx,
0213 unsigned int reg)
0214 {
0215 return readq(ctx->regs + reg);
0216 }
0217
0218 static unsigned int regmap_mmio_read64le_relaxed(struct regmap_mmio_context *ctx,
0219 unsigned int reg)
0220 {
0221 return readq_relaxed(ctx->regs + reg);
0222 }
0223 #endif
0224
0225 static int regmap_mmio_read(void *context, unsigned int reg, unsigned int *val)
0226 {
0227 struct regmap_mmio_context *ctx = context;
0228 int ret;
0229
0230 if (!IS_ERR(ctx->clk)) {
0231 ret = clk_enable(ctx->clk);
0232 if (ret < 0)
0233 return ret;
0234 }
0235
0236 *val = ctx->reg_read(ctx, reg);
0237
0238 if (!IS_ERR(ctx->clk))
0239 clk_disable(ctx->clk);
0240
0241 return 0;
0242 }
0243
0244 static void regmap_mmio_free_context(void *context)
0245 {
0246 struct regmap_mmio_context *ctx = context;
0247
0248 if (!IS_ERR(ctx->clk)) {
0249 clk_unprepare(ctx->clk);
0250 if (!ctx->attached_clk)
0251 clk_put(ctx->clk);
0252 }
0253 kfree(context);
0254 }
0255
0256 static const struct regmap_bus regmap_mmio = {
0257 .fast_io = true,
0258 .reg_write = regmap_mmio_write,
0259 .reg_read = regmap_mmio_read,
0260 .free_context = regmap_mmio_free_context,
0261 .val_format_endian_default = REGMAP_ENDIAN_LITTLE,
0262 };
0263
0264 static struct regmap_mmio_context *regmap_mmio_gen_context(struct device *dev,
0265 const char *clk_id,
0266 void __iomem *regs,
0267 const struct regmap_config *config)
0268 {
0269 struct regmap_mmio_context *ctx;
0270 int min_stride;
0271 int ret;
0272
0273 ret = regmap_mmio_regbits_check(config->reg_bits);
0274 if (ret)
0275 return ERR_PTR(ret);
0276
0277 if (config->pad_bits)
0278 return ERR_PTR(-EINVAL);
0279
0280 min_stride = regmap_mmio_get_min_stride(config->val_bits);
0281 if (min_stride < 0)
0282 return ERR_PTR(min_stride);
0283
0284 if (config->reg_stride < min_stride)
0285 return ERR_PTR(-EINVAL);
0286
0287 ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
0288 if (!ctx)
0289 return ERR_PTR(-ENOMEM);
0290
0291 ctx->regs = regs;
0292 ctx->val_bytes = config->val_bits / 8;
0293 ctx->relaxed_mmio = config->use_relaxed_mmio;
0294 ctx->clk = ERR_PTR(-ENODEV);
0295
0296 switch (regmap_get_val_endian(dev, ®map_mmio, config)) {
0297 case REGMAP_ENDIAN_DEFAULT:
0298 case REGMAP_ENDIAN_LITTLE:
0299 #ifdef __LITTLE_ENDIAN
0300 case REGMAP_ENDIAN_NATIVE:
0301 #endif
0302 switch (config->val_bits) {
0303 case 8:
0304 if (ctx->relaxed_mmio) {
0305 ctx->reg_read = regmap_mmio_read8_relaxed;
0306 ctx->reg_write = regmap_mmio_write8_relaxed;
0307 } else {
0308 ctx->reg_read = regmap_mmio_read8;
0309 ctx->reg_write = regmap_mmio_write8;
0310 }
0311 break;
0312 case 16:
0313 if (ctx->relaxed_mmio) {
0314 ctx->reg_read = regmap_mmio_read16le_relaxed;
0315 ctx->reg_write = regmap_mmio_write16le_relaxed;
0316 } else {
0317 ctx->reg_read = regmap_mmio_read16le;
0318 ctx->reg_write = regmap_mmio_write16le;
0319 }
0320 break;
0321 case 32:
0322 if (ctx->relaxed_mmio) {
0323 ctx->reg_read = regmap_mmio_read32le_relaxed;
0324 ctx->reg_write = regmap_mmio_write32le_relaxed;
0325 } else {
0326 ctx->reg_read = regmap_mmio_read32le;
0327 ctx->reg_write = regmap_mmio_write32le;
0328 }
0329 break;
0330 #ifdef CONFIG_64BIT
0331 case 64:
0332 if (ctx->relaxed_mmio) {
0333 ctx->reg_read = regmap_mmio_read64le_relaxed;
0334 ctx->reg_write = regmap_mmio_write64le_relaxed;
0335 } else {
0336 ctx->reg_read = regmap_mmio_read64le;
0337 ctx->reg_write = regmap_mmio_write64le;
0338 }
0339 break;
0340 #endif
0341 default:
0342 ret = -EINVAL;
0343 goto err_free;
0344 }
0345 break;
0346 case REGMAP_ENDIAN_BIG:
0347 #ifdef __BIG_ENDIAN
0348 case REGMAP_ENDIAN_NATIVE:
0349 #endif
0350 switch (config->val_bits) {
0351 case 8:
0352 ctx->reg_read = regmap_mmio_read8;
0353 ctx->reg_write = regmap_mmio_write8;
0354 break;
0355 case 16:
0356 ctx->reg_read = regmap_mmio_read16be;
0357 ctx->reg_write = regmap_mmio_write16be;
0358 break;
0359 case 32:
0360 ctx->reg_read = regmap_mmio_read32be;
0361 ctx->reg_write = regmap_mmio_write32be;
0362 break;
0363 default:
0364 ret = -EINVAL;
0365 goto err_free;
0366 }
0367 break;
0368 default:
0369 ret = -EINVAL;
0370 goto err_free;
0371 }
0372
0373 if (clk_id == NULL)
0374 return ctx;
0375
0376 ctx->clk = clk_get(dev, clk_id);
0377 if (IS_ERR(ctx->clk)) {
0378 ret = PTR_ERR(ctx->clk);
0379 goto err_free;
0380 }
0381
0382 ret = clk_prepare(ctx->clk);
0383 if (ret < 0) {
0384 clk_put(ctx->clk);
0385 goto err_free;
0386 }
0387
0388 return ctx;
0389
0390 err_free:
0391 kfree(ctx);
0392
0393 return ERR_PTR(ret);
0394 }
0395
0396 struct regmap *__regmap_init_mmio_clk(struct device *dev, const char *clk_id,
0397 void __iomem *regs,
0398 const struct regmap_config *config,
0399 struct lock_class_key *lock_key,
0400 const char *lock_name)
0401 {
0402 struct regmap_mmio_context *ctx;
0403
0404 ctx = regmap_mmio_gen_context(dev, clk_id, regs, config);
0405 if (IS_ERR(ctx))
0406 return ERR_CAST(ctx);
0407
0408 return __regmap_init(dev, ®map_mmio, ctx, config,
0409 lock_key, lock_name);
0410 }
0411 EXPORT_SYMBOL_GPL(__regmap_init_mmio_clk);
0412
0413 struct regmap *__devm_regmap_init_mmio_clk(struct device *dev,
0414 const char *clk_id,
0415 void __iomem *regs,
0416 const struct regmap_config *config,
0417 struct lock_class_key *lock_key,
0418 const char *lock_name)
0419 {
0420 struct regmap_mmio_context *ctx;
0421
0422 ctx = regmap_mmio_gen_context(dev, clk_id, regs, config);
0423 if (IS_ERR(ctx))
0424 return ERR_CAST(ctx);
0425
0426 return __devm_regmap_init(dev, ®map_mmio, ctx, config,
0427 lock_key, lock_name);
0428 }
0429 EXPORT_SYMBOL_GPL(__devm_regmap_init_mmio_clk);
0430
0431 int regmap_mmio_attach_clk(struct regmap *map, struct clk *clk)
0432 {
0433 struct regmap_mmio_context *ctx = map->bus_context;
0434
0435 ctx->clk = clk;
0436 ctx->attached_clk = true;
0437
0438 return clk_prepare(ctx->clk);
0439 }
0440 EXPORT_SYMBOL_GPL(regmap_mmio_attach_clk);
0441
0442 void regmap_mmio_detach_clk(struct regmap *map)
0443 {
0444 struct regmap_mmio_context *ctx = map->bus_context;
0445
0446 clk_unprepare(ctx->clk);
0447
0448 ctx->attached_clk = false;
0449 ctx->clk = NULL;
0450 }
0451 EXPORT_SYMBOL_GPL(regmap_mmio_detach_clk);
0452
0453 MODULE_LICENSE("GPL v2");