diff options
Diffstat (limited to 'drivers/base/regmap/regmap-mmio.c')
| -rw-r--r-- | drivers/base/regmap/regmap-mmio.c | 259 |
1 files changed, 139 insertions, 120 deletions
diff --git a/drivers/base/regmap/regmap-mmio.c b/drivers/base/regmap/regmap-mmio.c index eea51569f0eb..7526906ca080 100644 --- a/drivers/base/regmap/regmap-mmio.c +++ b/drivers/base/regmap/regmap-mmio.c | |||
| @@ -25,26 +25,14 @@ | |||
| 25 | 25 | ||
| 26 | struct regmap_mmio_context { | 26 | struct regmap_mmio_context { |
| 27 | void __iomem *regs; | 27 | void __iomem *regs; |
| 28 | unsigned reg_bytes; | ||
| 29 | unsigned val_bytes; | 28 | unsigned val_bytes; |
| 30 | unsigned pad_bytes; | ||
| 31 | struct clk *clk; | 29 | struct clk *clk; |
| 32 | }; | ||
| 33 | 30 | ||
| 34 | static inline void regmap_mmio_regsize_check(size_t reg_size) | 31 | void (*reg_write)(struct regmap_mmio_context *ctx, |
| 35 | { | 32 | unsigned int reg, unsigned int val); |
| 36 | switch (reg_size) { | 33 | unsigned int (*reg_read)(struct regmap_mmio_context *ctx, |
| 37 | case 1: | 34 | unsigned int reg); |
| 38 | case 2: | 35 | }; |
| 39 | case 4: | ||
| 40 | #ifdef CONFIG_64BIT | ||
| 41 | case 8: | ||
| 42 | #endif | ||
| 43 | break; | ||
| 44 | default: | ||
| 45 | BUG(); | ||
| 46 | } | ||
| 47 | } | ||
| 48 | 36 | ||
| 49 | static int regmap_mmio_regbits_check(size_t reg_bits) | 37 | static int regmap_mmio_regbits_check(size_t reg_bits) |
| 50 | { | 38 | { |
| @@ -88,72 +76,62 @@ static int regmap_mmio_get_min_stride(size_t val_bits) | |||
| 88 | return min_stride; | 76 | return min_stride; |
| 89 | } | 77 | } |
| 90 | 78 | ||
| 91 | static inline void regmap_mmio_count_check(size_t count, u32 offset) | 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) | ||
| 92 | { | 89 | { |
| 93 | BUG_ON(count <= offset); | 90 | writew(val, ctx->regs + reg); |
| 94 | } | 91 | } |
| 95 | 92 | ||
| 96 | static inline unsigned int | 93 | static void regmap_mmio_write16be(struct regmap_mmio_context *ctx, |
| 97 | regmap_mmio_get_offset(const void *reg, size_t reg_size) | 94 | unsigned int reg, |
| 95 | unsigned int val) | ||
| 98 | { | 96 | { |
| 99 | switch (reg_size) { | 97 | iowrite16be(val, ctx->regs + reg); |
| 100 | case 1: | 98 | } |
| 101 | return *(u8 *)reg; | 99 | |
| 102 | case 2: | 100 | static void regmap_mmio_write32le(struct regmap_mmio_context *ctx, |
| 103 | return *(u16 *)reg; | 101 | unsigned int reg, |
| 104 | case 4: | 102 | unsigned int val) |
| 105 | return *(u32 *)reg; | 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 | |||
| 106 | #ifdef CONFIG_64BIT | 114 | #ifdef CONFIG_64BIT |
| 107 | case 8: | 115 | static void regmap_mmio_write64le(struct regmap_mmio_context *ctx, |
| 108 | return *(u64 *)reg; | 116 | unsigned int reg, |
| 109 | #endif | 117 | unsigned int val) |
| 110 | default: | 118 | { |
| 111 | BUG(); | 119 | writeq(val, ctx->regs + reg); |
| 112 | } | ||
| 113 | } | 120 | } |
| 121 | #endif | ||
| 114 | 122 | ||
| 115 | static int regmap_mmio_gather_write(void *context, | 123 | static int regmap_mmio_write(void *context, unsigned int reg, unsigned int val) |
| 116 | const void *reg, size_t reg_size, | ||
| 117 | const void *val, size_t val_size) | ||
| 118 | { | 124 | { |
| 119 | struct regmap_mmio_context *ctx = context; | 125 | struct regmap_mmio_context *ctx = context; |
| 120 | unsigned int offset; | ||
| 121 | int ret; | 126 | int ret; |
| 122 | 127 | ||
| 123 | regmap_mmio_regsize_check(reg_size); | ||
| 124 | |||
| 125 | if (!IS_ERR(ctx->clk)) { | 128 | if (!IS_ERR(ctx->clk)) { |
| 126 | ret = clk_enable(ctx->clk); | 129 | ret = clk_enable(ctx->clk); |
| 127 | if (ret < 0) | 130 | if (ret < 0) |
| 128 | return ret; | 131 | return ret; |
| 129 | } | 132 | } |
| 130 | 133 | ||
| 131 | offset = regmap_mmio_get_offset(reg, reg_size); | 134 | ctx->reg_write(ctx, reg, val); |
| 132 | |||
| 133 | while (val_size) { | ||
| 134 | switch (ctx->val_bytes) { | ||
| 135 | case 1: | ||
| 136 | writeb(*(u8 *)val, ctx->regs + offset); | ||
| 137 | break; | ||
| 138 | case 2: | ||
| 139 | writew(*(u16 *)val, ctx->regs + offset); | ||
| 140 | break; | ||
| 141 | case 4: | ||
| 142 | writel(*(u32 *)val, ctx->regs + offset); | ||
| 143 | break; | ||
| 144 | #ifdef CONFIG_64BIT | ||
| 145 | case 8: | ||
| 146 | writeq(*(u64 *)val, ctx->regs + offset); | ||
| 147 | break; | ||
| 148 | #endif | ||
| 149 | default: | ||
| 150 | /* Should be caught by regmap_mmio_check_config */ | ||
| 151 | BUG(); | ||
| 152 | } | ||
| 153 | val_size -= ctx->val_bytes; | ||
| 154 | val += ctx->val_bytes; | ||
| 155 | offset += ctx->val_bytes; | ||
| 156 | } | ||
| 157 | 135 | ||
| 158 | if (!IS_ERR(ctx->clk)) | 136 | if (!IS_ERR(ctx->clk)) |
| 159 | clk_disable(ctx->clk); | 137 | clk_disable(ctx->clk); |
| @@ -161,59 +139,56 @@ static int regmap_mmio_gather_write(void *context, | |||
| 161 | return 0; | 139 | return 0; |
| 162 | } | 140 | } |
| 163 | 141 | ||
| 164 | static int regmap_mmio_write(void *context, const void *data, size_t count) | 142 | static unsigned int regmap_mmio_read8(struct regmap_mmio_context *ctx, |
| 143 | unsigned int reg) | ||
| 165 | { | 144 | { |
| 166 | struct regmap_mmio_context *ctx = context; | 145 | return readb(ctx->regs + reg); |
| 167 | unsigned int offset = ctx->reg_bytes + ctx->pad_bytes; | 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 | } | ||
| 168 | 165 | ||
| 169 | regmap_mmio_count_check(count, offset); | 166 | static unsigned int regmap_mmio_read32be(struct regmap_mmio_context *ctx, |
| 167 | unsigned int reg) | ||
| 168 | { | ||
| 169 | return ioread32be(ctx->regs + reg); | ||
| 170 | } | ||
| 170 | 171 | ||
| 171 | return regmap_mmio_gather_write(context, data, ctx->reg_bytes, | 172 | #ifdef CONFIG_64BIT |
| 172 | data + offset, count - offset); | 173 | static unsigned int regmap_mmio_read64le(struct regmap_mmio_context *ctx, |
| 174 | unsigned int reg) | ||
| 175 | { | ||
| 176 | return readq(ctx->regs + reg); | ||
| 173 | } | 177 | } |
| 178 | #endif | ||
| 174 | 179 | ||
| 175 | static int regmap_mmio_read(void *context, | 180 | static int regmap_mmio_read(void *context, unsigned int reg, unsigned int *val) |
| 176 | const void *reg, size_t reg_size, | ||
| 177 | void *val, size_t val_size) | ||
| 178 | { | 181 | { |
| 179 | struct regmap_mmio_context *ctx = context; | 182 | struct regmap_mmio_context *ctx = context; |
| 180 | unsigned int offset; | ||
| 181 | int ret; | 183 | int ret; |
| 182 | 184 | ||
| 183 | regmap_mmio_regsize_check(reg_size); | ||
| 184 | |||
| 185 | if (!IS_ERR(ctx->clk)) { | 185 | if (!IS_ERR(ctx->clk)) { |
| 186 | ret = clk_enable(ctx->clk); | 186 | ret = clk_enable(ctx->clk); |
| 187 | if (ret < 0) | 187 | if (ret < 0) |
| 188 | return ret; | 188 | return ret; |
| 189 | } | 189 | } |
| 190 | 190 | ||
| 191 | offset = regmap_mmio_get_offset(reg, reg_size); | 191 | *val = ctx->reg_read(ctx, reg); |
| 192 | |||
| 193 | while (val_size) { | ||
| 194 | switch (ctx->val_bytes) { | ||
| 195 | case 1: | ||
| 196 | *(u8 *)val = readb(ctx->regs + offset); | ||
| 197 | break; | ||
| 198 | case 2: | ||
| 199 | *(u16 *)val = readw(ctx->regs + offset); | ||
| 200 | break; | ||
| 201 | case 4: | ||
| 202 | *(u32 *)val = readl(ctx->regs + offset); | ||
| 203 | break; | ||
| 204 | #ifdef CONFIG_64BIT | ||
| 205 | case 8: | ||
| 206 | *(u64 *)val = readq(ctx->regs + offset); | ||
| 207 | break; | ||
| 208 | #endif | ||
| 209 | default: | ||
| 210 | /* Should be caught by regmap_mmio_check_config */ | ||
| 211 | BUG(); | ||
| 212 | } | ||
| 213 | val_size -= ctx->val_bytes; | ||
| 214 | val += ctx->val_bytes; | ||
| 215 | offset += ctx->val_bytes; | ||
| 216 | } | ||
| 217 | 192 | ||
| 218 | if (!IS_ERR(ctx->clk)) | 193 | if (!IS_ERR(ctx->clk)) |
| 219 | clk_disable(ctx->clk); | 194 | clk_disable(ctx->clk); |
| @@ -232,14 +207,11 @@ static void regmap_mmio_free_context(void *context) | |||
| 232 | kfree(context); | 207 | kfree(context); |
| 233 | } | 208 | } |
| 234 | 209 | ||
| 235 | static struct regmap_bus regmap_mmio = { | 210 | static const struct regmap_bus regmap_mmio = { |
| 236 | .fast_io = true, | 211 | .fast_io = true, |
| 237 | .write = regmap_mmio_write, | 212 | .reg_write = regmap_mmio_write, |
| 238 | .gather_write = regmap_mmio_gather_write, | 213 | .reg_read = regmap_mmio_read, |
| 239 | .read = regmap_mmio_read, | ||
| 240 | .free_context = regmap_mmio_free_context, | 214 | .free_context = regmap_mmio_free_context, |
| 241 | .reg_format_endian_default = REGMAP_ENDIAN_NATIVE, | ||
| 242 | .val_format_endian_default = REGMAP_ENDIAN_NATIVE, | ||
| 243 | }; | 215 | }; |
| 244 | 216 | ||
| 245 | static struct regmap_mmio_context *regmap_mmio_gen_context(struct device *dev, | 217 | static struct regmap_mmio_context *regmap_mmio_gen_context(struct device *dev, |
| @@ -265,24 +237,71 @@ static struct regmap_mmio_context *regmap_mmio_gen_context(struct device *dev, | |||
| 265 | if (config->reg_stride < min_stride) | 237 | if (config->reg_stride < min_stride) |
| 266 | return ERR_PTR(-EINVAL); | 238 | return ERR_PTR(-EINVAL); |
| 267 | 239 | ||
| 268 | switch (config->reg_format_endian) { | ||
| 269 | case REGMAP_ENDIAN_DEFAULT: | ||
| 270 | case REGMAP_ENDIAN_NATIVE: | ||
| 271 | break; | ||
| 272 | default: | ||
| 273 | return ERR_PTR(-EINVAL); | ||
| 274 | } | ||
| 275 | |||
| 276 | ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); | 240 | ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); |
| 277 | if (!ctx) | 241 | if (!ctx) |
| 278 | return ERR_PTR(-ENOMEM); | 242 | return ERR_PTR(-ENOMEM); |
| 279 | 243 | ||
| 280 | ctx->regs = regs; | 244 | ctx->regs = regs; |
| 281 | ctx->val_bytes = config->val_bits / 8; | 245 | ctx->val_bytes = config->val_bits / 8; |
| 282 | ctx->reg_bytes = config->reg_bits / 8; | ||
| 283 | ctx->pad_bytes = config->pad_bits / 8; | ||
| 284 | ctx->clk = ERR_PTR(-ENODEV); | 246 | ctx->clk = ERR_PTR(-ENODEV); |
| 285 | 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 | |||
| 286 | if (clk_id == NULL) | 305 | if (clk_id == NULL) |
| 287 | return ctx; | 306 | return ctx; |
| 288 | 307 | ||
