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/init.h> 22 #include <linux/io.h> 23 #include <linux/module.h> 24 #include <linux/regmap.h> 25 #include <linux/slab.h> 26 27 struct regmap_mmio_context { 28 void __iomem *regs; 29 unsigned val_bytes; 30 struct clk *clk; 31 }; 32 33 static int regmap_mmio_gather_write(void *context, 34 const void *reg, size_t reg_size, 35 const void *val, size_t val_size) 36 { 37 struct regmap_mmio_context *ctx = context; 38 u32 offset; 39 int ret; 40 41 BUG_ON(reg_size != 4); 42 43 if (ctx->clk) { 44 ret = clk_enable(ctx->clk); 45 if (ret < 0) 46 return ret; 47 } 48 49 offset = *(u32 *)reg; 50 51 while (val_size) { 52 switch (ctx->val_bytes) { 53 case 1: 54 writeb(*(u8 *)val, ctx->regs + offset); 55 break; 56 case 2: 57 writew(*(u16 *)val, ctx->regs + offset); 58 break; 59 case 4: 60 writel(*(u32 *)val, ctx->regs + offset); 61 break; 62 #ifdef CONFIG_64BIT 63 case 8: 64 writeq(*(u64 *)val, ctx->regs + offset); 65 break; 66 #endif 67 default: 68 /* Should be caught by regmap_mmio_check_config */ 69 BUG(); 70 } 71 val_size -= ctx->val_bytes; 72 val += ctx->val_bytes; 73 offset += ctx->val_bytes; 74 } 75 76 if (ctx->clk) 77 clk_disable(ctx->clk); 78 79 return 0; 80 } 81 82 static int regmap_mmio_write(void *context, const void *data, size_t count) 83 { 84 BUG_ON(count < 4); 85 86 return regmap_mmio_gather_write(context, data, 4, data + 4, count - 4); 87 } 88 89 static int regmap_mmio_read(void *context, 90 const void *reg, size_t reg_size, 91 void *val, size_t val_size) 92 { 93 struct regmap_mmio_context *ctx = context; 94 u32 offset; 95 int ret; 96 97 BUG_ON(reg_size != 4); 98 99 if (ctx->clk) { 100 ret = clk_enable(ctx->clk); 101 if (ret < 0) 102 return ret; 103 } 104 105 offset = *(u32 *)reg; 106 107 while (val_size) { 108 switch (ctx->val_bytes) { 109 case 1: 110 *(u8 *)val = readb(ctx->regs + offset); 111 break; 112 case 2: 113 *(u16 *)val = readw(ctx->regs + offset); 114 break; 115 case 4: 116 *(u32 *)val = readl(ctx->regs + offset); 117 break; 118 #ifdef CONFIG_64BIT 119 case 8: 120 *(u64 *)val = readq(ctx->regs + offset); 121 break; 122 #endif 123 default: 124 /* Should be caught by regmap_mmio_check_config */ 125 BUG(); 126 } 127 val_size -= ctx->val_bytes; 128 val += ctx->val_bytes; 129 offset += ctx->val_bytes; 130 } 131 132 if (ctx->clk) 133 clk_disable(ctx->clk); 134 135 return 0; 136 } 137 138 static void regmap_mmio_free_context(void *context) 139 { 140 struct regmap_mmio_context *ctx = context; 141 142 if (ctx->clk) { 143 clk_unprepare(ctx->clk); 144 clk_put(ctx->clk); 145 } 146 kfree(context); 147 } 148 149 static struct regmap_bus regmap_mmio = { 150 .fast_io = true, 151 .write = regmap_mmio_write, 152 .gather_write = regmap_mmio_gather_write, 153 .read = regmap_mmio_read, 154 .free_context = regmap_mmio_free_context, 155 .reg_format_endian_default = REGMAP_ENDIAN_NATIVE, 156 .val_format_endian_default = REGMAP_ENDIAN_NATIVE, 157 }; 158 159 static struct regmap_mmio_context *regmap_mmio_gen_context(struct device *dev, 160 const char *clk_id, 161 void __iomem *regs, 162 const struct regmap_config *config) 163 { 164 struct regmap_mmio_context *ctx; 165 int min_stride; 166 int ret; 167 168 if (config->reg_bits != 32) 169 return ERR_PTR(-EINVAL); 170 171 if (config->pad_bits) 172 return ERR_PTR(-EINVAL); 173 174 switch (config->val_bits) { 175 case 8: 176 /* The core treats 0 as 1 */ 177 min_stride = 0; 178 break; 179 case 16: 180 min_stride = 2; 181 break; 182 case 32: 183 min_stride = 4; 184 break; 185 #ifdef CONFIG_64BIT 186 case 64: 187 min_stride = 8; 188 break; 189 #endif 190 break; 191 default: 192 return ERR_PTR(-EINVAL); 193 } 194 195 if (config->reg_stride < min_stride) 196 return ERR_PTR(-EINVAL); 197 198 switch (config->reg_format_endian) { 199 case REGMAP_ENDIAN_DEFAULT: 200 case REGMAP_ENDIAN_NATIVE: 201 break; 202 default: 203 return ERR_PTR(-EINVAL); 204 } 205 206 ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); 207 if (!ctx) 208 return ERR_PTR(-ENOMEM); 209 210 ctx->regs = regs; 211 ctx->val_bytes = config->val_bits / 8; 212 213 if (clk_id == NULL) 214 return ctx; 215 216 ctx->clk = clk_get(dev, clk_id); 217 if (IS_ERR(ctx->clk)) { 218 ret = PTR_ERR(ctx->clk); 219 goto err_free; 220 } 221 222 ret = clk_prepare(ctx->clk); 223 if (ret < 0) { 224 clk_put(ctx->clk); 225 goto err_free; 226 } 227 228 return ctx; 229 230 err_free: 231 kfree(ctx); 232 233 return ERR_PTR(ret); 234 } 235 236 /** 237 * regmap_init_mmio_clk(): Initialise register map with register clock 238 * 239 * @dev: Device that will be interacted with 240 * @clk_id: register clock consumer ID 241 * @regs: Pointer to memory-mapped IO region 242 * @config: Configuration for register map 243 * 244 * The return value will be an ERR_PTR() on error or a valid pointer to 245 * a struct regmap. 246 */ 247 struct regmap *regmap_init_mmio_clk(struct device *dev, const char *clk_id, 248 void __iomem *regs, 249 const struct regmap_config *config) 250 { 251 struct regmap_mmio_context *ctx; 252 253 ctx = regmap_mmio_gen_context(dev, clk_id, regs, config); 254 if (IS_ERR(ctx)) 255 return ERR_CAST(ctx); 256 257 return regmap_init(dev, ®map_mmio, ctx, config); 258 } 259 EXPORT_SYMBOL_GPL(regmap_init_mmio_clk); 260 261 /** 262 * devm_regmap_init_mmio_clk(): Initialise managed register map with clock 263 * 264 * @dev: Device that will be interacted with 265 * @clk_id: register clock consumer ID 266 * @regs: Pointer to memory-mapped IO region 267 * @config: Configuration for register map 268 * 269 * The return value will be an ERR_PTR() on error or a valid pointer 270 * to a struct regmap. The regmap will be automatically freed by the 271 * device management code. 272 */ 273 struct regmap *devm_regmap_init_mmio_clk(struct device *dev, const char *clk_id, 274 void __iomem *regs, 275 const struct regmap_config *config) 276 { 277 struct regmap_mmio_context *ctx; 278 279 ctx = regmap_mmio_gen_context(dev, clk_id, regs, config); 280 if (IS_ERR(ctx)) 281 return ERR_CAST(ctx); 282 283 return devm_regmap_init(dev, ®map_mmio, ctx, config); 284 } 285 EXPORT_SYMBOL_GPL(devm_regmap_init_mmio_clk); 286 287 MODULE_LICENSE("GPL v2"); 288