root/drivers/base/regmap/regmap-mmio.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. regmap_mmio_regbits_check
  2. regmap_mmio_get_min_stride
  3. regmap_mmio_write8
  4. regmap_mmio_write16le
  5. regmap_mmio_write16be
  6. regmap_mmio_write32le
  7. regmap_mmio_write32be
  8. regmap_mmio_write64le
  9. regmap_mmio_write
  10. regmap_mmio_read8
  11. regmap_mmio_read16le
  12. regmap_mmio_read16be
  13. regmap_mmio_read32le
  14. regmap_mmio_read32be
  15. regmap_mmio_read64le
  16. regmap_mmio_read
  17. regmap_mmio_free_context
  18. regmap_mmio_gen_context
  19. __regmap_init_mmio_clk
  20. __devm_regmap_init_mmio_clk
  21. regmap_mmio_attach_clk
  22. regmap_mmio_detach_clk

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

/* [<][>][^][v][top][bottom][index][help] */